home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir37 / ms_sh23s.zip / SRC / SH9.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  65KB  |  3,090 lines

  1. /*
  2.  * MS-DOS SHELL - History Processing
  3.  *
  4.  * MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited
  5.  *
  6.  * This code is subject to the following copyright restrictions:
  7.  *
  8.  * 1.  Redistribution and use in source and binary forms are permitted
  9.  *     provided that the above copyright notice is duplicated in the
  10.  *     source form and the copyright notice in file sh6.c is displayed
  11.  *     on entry to the program.
  12.  *
  13.  * 2.  The sources (or parts thereof) or objects generated from the sources
  14.  *     (or parts of sources) cannot be sold under any circumstances.
  15.  *
  16.  *    $Header: /usr/users/istewart/shell/sh2.3/Release/RCS/sh9.c,v 2.18 1994/08/25 20:49:11 istewart Exp $
  17.  *
  18.  *    $Log: sh9.c,v $
  19.  *    Revision 2.18  1994/08/25  20:49:11  istewart
  20.  *    MS Shell 2.3 Release
  21.  *
  22.  *    Revision 2.17  1994/02/23  09:23:38  istewart
  23.  *    Beta 233 updates
  24.  *
  25.  *    Revision 2.16  1994/02/01  10:25:20  istewart
  26.  *    Release 2.3 Beta 2, including first NT port
  27.  *
  28.  *    Revision 2.15  1994/01/20  14:51:43  istewart
  29.  *    Release 2.3 Beta 1
  30.  *
  31.  *    Revision 2.14  1994/01/11  17:55:25  istewart
  32.  *    Release 2.3 Beta 0 patches
  33.  *
  34.  *    Revision 2.13  1993/11/09  10:39:49  istewart
  35.  *    Beta 226 checking
  36.  *
  37.  *    Revision 2.12  1993/08/25  16:03:57  istewart
  38.  *    Beta 225 - see Notes file
  39.  *
  40.  *    Revision 2.11  1993/07/02  10:21:35  istewart
  41.  *    224 Beta fixes
  42.  *
  43.  *    Revision 2.10  1993/06/16  13:50:00  istewart
  44.  *    Fix defaults for Key initialisation
  45.  *
  46.  *    Revision 2.9  1993/06/14  11:00:12  istewart
  47.  *    More changes for 223 beta
  48.  *
  49.  *    Revision 2.8  1993/06/02  09:52:35  istewart
  50.  *    Beta 223 Updates - see Notes file
  51.  *
  52.  *    Revision 2.7  1993/02/16  16:03:15  istewart
  53.  *    Beta 2.22 Release
  54.  *
  55.  *    Revision 2.6  1993/01/26  18:35:09  istewart
  56.  *    Release 2.2 beta 0
  57.  *
  58.  *    Revision 2.5  1992/12/14  10:54:56  istewart
  59.  *    BETA 215 Fixes and 2.1 Release
  60.  *
  61.  *    Revision 2.4  1992/11/06  10:03:44  istewart
  62.  *    214 Beta test updates
  63.  *
  64.  *    Revision 2.3  1992/09/03  18:54:45  istewart
  65.  *    Beta 213 Updates
  66.  *
  67.  *    Revision 2.2  1992/07/16  14:33:34  istewart
  68.  *    Beta 212 Baseline
  69.  *
  70.  *    Revision 2.1  1992/07/10  10:52:48  istewart
  71.  *    211 Beta updates
  72.  *
  73.  *    Revision 2.0  1992/05/07  21:33:35  Ian_Stewartson
  74.  *    MS-Shell 2.0 Baseline release
  75.  *
  76.  */
  77.  
  78. #include <sys/types.h>
  79. #include <sys/stat.h>
  80. #include <stdio.h>
  81. #include <string.h>
  82. #include <ctype.h>
  83. #include <signal.h>
  84. #include <stdlib.h>
  85. #include <stddef.h>
  86. #include <errno.h>
  87. #include <setjmp.h>
  88. #include <limits.h>
  89. #include <unistd.h>
  90. #include <dirent.h>
  91. #include "sh.h"
  92.  
  93. #if (OS_TYPE == OS_UNIX)
  94. #  include <termios.h>
  95. #endif
  96.  
  97. #if (OS_TYPE == OS_DOS)
  98. #  ifndef _NKEYBRD_READ
  99. #    define _NKEYBRD_READ        0x10    /* read next char from kbd */
  100. #    define _NKEYBRD_READY        0x11    /* check for keystroke    */
  101. #    define _NKEYBRD_SHIFTSTATUS    0x12    /* get shift key status    */
  102. #  endif
  103.  
  104. #  ifndef _KEYBRD_READ        
  105. #    define _KEYBRD_READ               0x00    /* read next char from kbd */
  106. #    define _KEYBRD_READY              0x01    /* check for keystroke    */
  107. #    define _KEYBRD_SHIFTSTATUS        0x02    /* get shift key status    */
  108. #  endif
  109.  
  110. #  if defined (__TURBOC__)
  111. #    define _bios_keybrd(a)        bioskey (a)
  112. #  elif defined (__EMX__)
  113. unsigned int                 _bios_keybrd (unsigned int);
  114. #  endif
  115. #endif
  116.  
  117. /* Keyboard functions */
  118.  
  119. #define KF_LENGTH            ARRAY_SIZE (KF_List)
  120.  
  121. /*
  122.  * Saved command line structure
  123.  */
  124.  
  125. struct    cmd_history {
  126.     int        number;
  127.     char    *command;
  128. };
  129.  
  130. /* Function Declarations */
  131.  
  132. static bool F_LOCAL    ProcessAlphaNumericKey (int);
  133. static bool F_LOCAL    ProcessFunctionKey (int);
  134. static bool F_LOCAL    Process_History (int);
  135. static bool F_LOCAL    ScanHistory (void);
  136. static void F_LOCAL    ReDisplayInputLine (void);
  137. static void F_LOCAL    PageHistoryRecord (int);
  138. static bool F_LOCAL    UpdateConsoleInputLine (char *);
  139. static bool F_LOCAL    ReStartInput (char *);
  140. static void F_LOCAL    GenerateNewCursorPosition (void);
  141. static void F_LOCAL    EraseToEndOfLine (void);
  142. static bool F_LOCAL    CompleteFileName (char *, bool);
  143. static void F_LOCAL    InitialiseInput (bool);
  144. static void F_LOCAL    PrintOutHistory (FILE *, bool, struct cmd_history *);
  145. static void F_LOCAL    ReleaseCommandMemory (struct cmd_history *);
  146. static void F_LOCAL    SaveCurrentHistory (void);
  147. static void F_LOCAL    memrcpy (char *, char *, int);
  148. static FILE * F_LOCAL    OpenHistoryFile (char *);
  149. static void F_LOCAL    GetLineFromConsole (void);
  150. #ifdef KEYDEBUG
  151. static void        DisplayKeyCode (unsigned int, unsigned int);
  152. #else
  153. #  define DisplayKeyCode(a,b)
  154. #endif
  155.  
  156.  
  157. #if (OS_TYPE != OS_DOS) 
  158. static void F_LOCAL    ChangeKeyboardMode (bool);
  159. #else
  160. #  define ChangeKeyboardMode(a)
  161. #endif
  162.  
  163. #if (OS_TYPE == OS_NT)
  164. static bool F_LOCAL    DoNTKeyMap (KEY_EVENT_RECORD *);
  165. #endif
  166.  
  167. #if (OS_TYPE == OS_DOS) && (OS_SIZE == OS_16)
  168. static bool        DESQviewActive = FALSE;/* Poll keyboard        */
  169. #endif
  170.  
  171. static bool F_LOCAL    InsertACharacter (int);
  172. static int F_LOCAL    OutputACharacter (int);
  173. static int F_LOCAL    GetLineFromDevice (void);
  174.  
  175. #if (OS_TYPE == OS_DOS)
  176. static void F_LOCAL    CheckKeyboardPolling (void);
  177.                     /* Read keyboard parameter    */
  178. static unsigned int    ReadKeyboardOption = _KEYBRD_READ;
  179. #else
  180. #  define CheckKeyboardPolling()
  181. #endif
  182.  
  183. static bool    InsertMode = FALSE;
  184. static char    *c_buffer_pos;        /* Position in command line    */
  185. static char    *EndOfCurrentLine;    /* End of command line        */
  186. static int    m_line = 0;        /* Max write line number    */
  187. static int    c_history = -1;        /* Current entry        */
  188. static int    l_history = 0;        /* End of history array        */
  189. static int    M_length = -1;        /* Match length            */
  190. static int    MaxLength = 0;        /* Max line length        */
  191. static int    OldMaxLength = 0;    /* Previous Max line length    */
  192. static int    CurrentHistorySize = 0;    /* Current Length of History    */
  193.                     /* Array            */
  194. static bool    AppendHistory = FALSE;    /* Append to history        */
  195. static bool    SaveHistory = FALSE;    /* Save history            */
  196. static char    *No_prehistory   = "No previous commands";
  197. static char    *No_MatchHistory = "No history match found";
  198. static char    *No_posthistory  = "No more commands";
  199. static char    *History_2long   = "History line too long";
  200.  
  201. #if (OS_TYPE == OS_NT)
  202. static HANDLE    NT_StdIn;        /* Standard Input handler    */
  203. static HANDLE    NT_StdOut;        /* Standard Ouput handler    */
  204.  
  205. #define CTRL_PRESSED    ((LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
  206. #define ALT_PRESSED    ((LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
  207.  
  208. /* Scan codes to ignore on input */
  209.  
  210. static WORD    IgnoreScanCode[] = {
  211.     0x1d,                /* Control key            */
  212.     0x38,                /* Alt key            */
  213.     0x2a,                /* Shift key            */
  214.     0x36,                /* Shift key            */
  215.     0x3a,                /* Caps key            */
  216.     0x45                /* Numlock key            */
  217. };
  218.  
  219. #define IGNORE_CNT    ARRAY_SIZE (IgnoreScanCode) 
  220.  
  221. /* Mapping table because we don't get converted scan codes */
  222.  
  223.  
  224. struct NT_KFMap {
  225.     unsigned char    Normal;        /* Normal scancode    */
  226.     unsigned char    Shift;        /* shift scancode    */
  227.     unsigned char    Control;    /* Control scancode    */
  228.     unsigned char    Alt;        /* Alt scancode        */
  229. } NT_KFMap [] =  {
  230.     /* Key         Normal  Shift-  Control-  Alt-    */
  231.     { /* F1 */        0x3b,   0x54,   0x5E,     0x68 },
  232.     { /* F2 */        0x3c,   0x55,   0x5F,     0x69 },
  233.     { /* F3 */        0x3d,   0x56,   0x60,     0x6A },
  234.     { /* F4 */        0x3e,   0x57,   0x61,     0x6B },
  235.     { /* F5 */        0x3f,   0x58,   0x62,     0x6C },
  236.     { /* F6 */        0x40,   0x59,   0x63,     0x6D },
  237.     { /* F7 */        0x41,   0x5A,   0x64,     0x6E },
  238.     { /* F8 */        0x42,   0x5B,   0x65,     0x6F },
  239.     { /* F9 */        0x43,   0x5C,   0x66,     0x70 },
  240.     { /* F10 */        0x44,   0x5D,   0x67,     0x71 },
  241.     { /* F11 */        0x85,   0x87,   0x89,     0x8b },
  242.     { /* F12 */        0x86,   0x88,   0x8a,     0x8c },
  243.  
  244.     { /* INSERT */    0x52,   0x52,   0x00,     0x00 },
  245.     { /* HOME */    0x47,   0x47,   0x77,     0x00 },
  246.     { /* PAGE UP */    0x49,   0x49,   0x84,     0x00 },
  247.     { /* DELETE */    0x53,   0x53,   0x00,     0x00 },
  248.     { /* END */        0x4f,   0x4f,   0x75,     0x00 },
  249.     { /* PAGE DOWN */    0x51,   0x51,   0x76,     0x00 },
  250.  
  251.     { /* UP ARROW */    0x48,   0x48,   0x00,     0x00 },
  252.     { /* LEFT ARROW */    0x4b,   0x4b,   0x73,     0x00 },
  253.     { /* DOWN ARROW */    0x50,   0x50,   0x00,     0x00 },
  254.     { /* RIGHT ARROW */    0x4d,   0x4d,   0x74,     0x00 },
  255. };
  256.  
  257. #define MAX_NT_FKMAP    ARRAY_SIZE (NT_KFMap)
  258. #endif
  259.  
  260. /* Function Key table */
  261.  
  262. static struct Key_Fun_List {
  263.     char        *kf_name;
  264.     unsigned char    akey;
  265.     unsigned char    fkey;
  266.     unsigned char    fcode;
  267. } KF_List[] = {
  268.     { "ScanBackward",    0,    'I',    KF_SCANBACKWARD },
  269.     { "ScanForeward",    0,    'Q',    KF_SCANFOREWARD },
  270.     { "Previous",    0,    'H',    KF_PREVIOUS },
  271.     { "Next",        0,    'P',    KF_NEXT },
  272.     { "Left",        0,    'K',    KF_LEFT },
  273.     { "Right",        0,    'M',    KF_RIGHT },
  274.     { "WordRight",    0,    't',    KF_WORDRIGHT },
  275.     { "WordLeft",    0,    's',    KF_WORDLEFT },
  276.     { "Start",        0,    'G',    KF_START },
  277.     { "Clear",        0x0ff,    'v',    KF_CLEAR },
  278.     { "Flush",        0,    'u',    KF_FLUSH },
  279.     { "End",        0,    'O',    KF_END },
  280.     { "Insert",        0,    'R',    KF_INSERT },
  281.     { "DeleteRight",    0,    'S',    KF_DELETERIGHT },
  282.     { "DeleteLeft",    CHAR_BACKSPACE,    0,    KF_DELETELEFT },
  283.     { "Complete",    0,    'w',    KF_COMPLETE },
  284.     { "Directory",    0,    0x0f,    KF_DIRECTORY },
  285.     { "ClearScreen",    0,    0x84,    KF_CLEARSCREEN },
  286.     { "Jobs",        0,    0x68,    KF_JOBS },
  287.     { "Transpose",    0x14,    0,    KF_TRANSPOSE },
  288.     { "Quote",        0x11,    0,    KF_QUOTE },
  289.  
  290. /* End of function keys - flags */
  291.  
  292.     { "Bell",        1,    0,    KF_RINGBELL },
  293.     { "HalfHeight",    0,    0,    KF_HALFHEIGTH },
  294.     { "InsertMode",    0,    0,    KF_INSERTMODE },
  295.     { "InsertCursor",    1,    0,    KF_INSERTCURSOR },
  296.     { "RootDrive",    0,    0,    KF_ROOTDRIVE },
  297.     { "EOFKey",        4,    0,    KF_EOFKEY },
  298. };
  299.  
  300. /* Arrary of history Items */
  301.  
  302. static struct cmd_history    *cmd_history = (struct cmd_history *)NULL;
  303.  
  304. /*
  305.  * Processing standard input.  Editting is only supported on OS/2 at the
  306.  * moment.
  307.  */
  308.  
  309. int GetConsoleInput (void)
  310. {
  311.     bool    console = C2bool (IS_Console (0));
  312.     int        RetVal = 0;
  313.  
  314. /* Has dofc set the flag to say use the console buffer ? */
  315.  
  316.     if (UseConsoleBuffer)
  317.     {
  318.     UseConsoleBuffer = FALSE;
  319.     SaveHistory = TRUE;
  320.     SaveCurrentHistory ();
  321.     SaveHistory = FALSE;
  322.     }
  323.  
  324. /*
  325.  * Read in a line from the console
  326.  */
  327.  
  328.     else
  329.     {
  330.  
  331. /* Set to last history item */
  332.  
  333.     if (FL_TEST (FLAG_INTERACTIVE) || (IS_TTY (0) && IS_TTY (1)))
  334.         SaveCurrentHistory ();
  335.  
  336. /* Zap the line and output the prompt.  Save history status info */
  337.  
  338.     memset (ConsoleLineBuffer, 0, LINE_MAX + 1);
  339.  
  340.     if (FL_TEST (FLAG_INTERACTIVE) || (IS_TTY (0) && IS_TTY (1)))
  341.     {
  342.         bool    o_SaveHistory = SaveHistory;
  343.  
  344.         OutputUserPrompt (LastUserPrompt);
  345.         SaveHistory = o_SaveHistory;
  346.     }
  347.  
  348. /* Only if we are working on the console and not via a pipe or file do we
  349.  * need to set up the console
  350.  */
  351.  
  352.     if (console)
  353.     {
  354.         CheckKeyboardPolling ();
  355.  
  356.         if (ChangeInitLoad)
  357.         {
  358.         ChangeInitLoad = FALSE;
  359.         Configure_Keys ();
  360.         }
  361.  
  362.         GetScreenParameters ();
  363.     }
  364.  
  365. /*
  366.  * Process the input.  If this is not the console, read from standard input
  367.  */
  368.  
  369.     if (!console)
  370.         RetVal = GetLineFromDevice ();
  371.  
  372.     else 
  373.     {
  374.         ChangeKeyboardMode (FALSE);
  375.  
  376. #if defined (FLAGS_VI) || defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
  377.         if (ShellGlobalFlags & FLAGS_EDITORS)
  378.         RetVal = EditorInput ();
  379.  
  380.         else
  381. #endif
  382.         GetLineFromConsole ();
  383.  
  384.         ChangeKeyboardMode (TRUE);
  385.     }
  386.  
  387.     if (LastUserPrompt == PS1)
  388.         LastUserPrompt = PS2;
  389.  
  390. /* Clean up */
  391.  
  392.     FlushStreams ();
  393.  
  394.     if (console)
  395.         SetCursorShape (FALSE);
  396.     }
  397.  
  398. /* Return any errors */
  399.  
  400.     if (RetVal < 0)
  401.         return 0;
  402.  
  403. /* If we are reading from the console, check for end of file.  From file or
  404.  * pipe, we detect this differently
  405.  */
  406.  
  407.     if (console)
  408.     {
  409.     if (*ConsoleLineBuffer == (char)KF_List[KF_EOFKEY].akey)
  410.         *ConsoleLineBuffer = 0;
  411.  
  412.     else
  413.         strcat (ConsoleLineBuffer, LIT_NewLine);
  414.     }
  415.  
  416.     return strlen (ConsoleLineBuffer);
  417. }
  418.  
  419. /*
  420.  * Read a line from a file or pipe - well pipe really.
  421.  */
  422.  
  423. static int F_LOCAL GetLineFromDevice (void)
  424. {
  425.     while (fgets (ConsoleLineBuffer, LINE_MAX, stdin) != (char *)NULL)
  426.     {
  427.     if (*ConsoleLineBuffer != CHAR_HISTORY)
  428.         return 0;
  429.     
  430.     else if (Process_History (0))
  431.     {
  432.         puts (ConsoleLineBuffer);
  433.         return 0;
  434.     }
  435.     }
  436.  
  437. /* EOF detected - return that fact */
  438.  
  439.     return -1;
  440. }
  441.  
  442. /*
  443.  * Read line from Console
  444.  */
  445.  
  446. static void F_LOCAL GetLineFromConsole (void)
  447. {
  448.     unsigned char    a_key, f_key;
  449.     int            i;
  450.  
  451. /* Process the input */
  452.  
  453.     while (TRUE)
  454.     {
  455.     InitialiseInput ((bool)KF_List[KF_INSERTMODE].akey);
  456.  
  457.     while (((a_key = ReadKeyBoard (&f_key)) != KF_List[KF_EOFKEY].akey) &&
  458.            (a_key != CHAR_NEW_LINE) && (a_key != CHAR_RETURN))
  459.     {
  460.  
  461. /* Handle Resize event */
  462.  
  463.         if (a_key == KT_RESIZE)
  464.         {
  465.         fputchar (CHAR_NEW_LINE);
  466.         GetScreenParameters ();
  467.         OutputUserPrompt (LastUserPrompt);
  468.         ReDisplayInputLine ();
  469.         continue;
  470.         }
  471.  
  472. /* Look up the keystroke to see if it is one of our functions */
  473.  
  474.         if (!(i = LookUpKeyBoardFunction (a_key, f_key)))
  475.         continue;
  476.  
  477.         if (((i > 0) ? ProcessAlphaNumericKey (i)
  478.                  : ProcessFunctionKey ((-i) - 1)))
  479.         ReDisplayInputLine ();
  480.  
  481. /* Handle a special case on insert mode on line 25 */
  482.  
  483.         if ((InsertMode) && (MaxLength > OldMaxLength) &&
  484.         (((StartCursorPosition + MaxLength) / MaximumColumns)
  485.             == MaximumLines) &&
  486.         (((StartCursorPosition + MaxLength) % MaximumColumns) == 0))
  487.         StartCursorPosition -= MaximumColumns;
  488.  
  489. /* Reposition the cursor */
  490.  
  491.         GenerateNewCursorPosition ();
  492.  
  493. /* Save old line length */
  494.  
  495.         OldMaxLength = MaxLength;
  496.     }
  497.  
  498. /* Terminate the line */
  499.  
  500.     *(c_buffer_pos = EndOfCurrentLine) = 0;
  501.     GenerateNewCursorPosition ();
  502.     fputchar (CHAR_NEW_LINE);
  503.     StartCursorPosition = -1;
  504.     FlushStreams ();
  505.  
  506. /* Line input - check for history */
  507.  
  508.     if ((*ConsoleLineBuffer == CHAR_HISTORY) && Process_History (0))
  509.     {
  510.         puts (ConsoleLineBuffer);
  511.         break;
  512.     }
  513.  
  514.     else if (*ConsoleLineBuffer != CHAR_HISTORY)
  515.         break;
  516.     }
  517.  
  518.     if (a_key == KF_List[KF_EOFKEY].akey)
  519.     *EndOfCurrentLine = KF_List[KF_EOFKEY].akey;
  520. }
  521.  
  522. /*
  523.  * Handler Alpha_numeric characters
  524.  */
  525.  
  526. static bool F_LOCAL ProcessAlphaNumericKey (int c)
  527. {
  528.     bool    redisplay = FALSE;
  529.  
  530. /* Normal character processing */
  531.  
  532.     if ((c_buffer_pos - ConsoleLineBuffer) == LINE_MAX)
  533.     return RingWarningBell ();
  534.  
  535.     else if (!InsertMode)
  536.     {
  537.     if (c_buffer_pos == EndOfCurrentLine)
  538.         ++EndOfCurrentLine;
  539.  
  540.     else if (iscntrl (*c_buffer_pos) || iscntrl (c))
  541.         redisplay = TRUE;
  542.  
  543.     *(c_buffer_pos++) = (char)c;
  544.  
  545.     if (redisplay || (c == CHAR_TAB))
  546.         return TRUE;
  547.  
  548. /* Output the character */
  549.  
  550.     OutputACharacter (c);
  551.     return FALSE;
  552.     }
  553.  
  554.     else
  555.     return InsertACharacter (c);
  556. }
  557.  
  558. /* Process function keys */
  559.  
  560. static bool F_LOCAL ProcessFunctionKey (int fn)
  561. {
  562.     bool    fn_search = FALSE;
  563.     char    tmp;
  564.  
  565.     switch (fn)
  566.     {
  567.     case KF_SCANBACKWARD:        /* Scan backwards in history    */
  568.     case KF_SCANFOREWARD:        /* Scan forewards in history    */
  569.         *EndOfCurrentLine = 0;
  570.  
  571.         if (M_length == -1)
  572.         M_length = strlen (ConsoleLineBuffer);
  573.  
  574.         PageHistoryRecord ((fn == KF_SCANBACKWARD) ? -1 : 1);
  575.         return TRUE;
  576.  
  577.     case KF_PREVIOUS:        /* Previous command        */
  578.         *EndOfCurrentLine = 0;
  579.         Process_History (-1);
  580.         return TRUE;
  581.  
  582.     case KF_NEXT:            /* Next command line        */
  583.         Process_History (1);
  584.         return TRUE;
  585.  
  586.     case KF_LEFT:            /* Cursor left            */
  587.         if (c_buffer_pos != ConsoleLineBuffer)
  588.         --c_buffer_pos;
  589.  
  590.         else
  591.         RingWarningBell ();
  592.  
  593.         return FALSE;
  594.  
  595.     case KF_RIGHT:            /* Cursor right            */
  596.         if (c_buffer_pos != EndOfCurrentLine)
  597.         ++c_buffer_pos;
  598.  
  599.         else
  600.         RingWarningBell ();
  601.  
  602.         return FALSE;
  603.  
  604.     case KF_WORDLEFT:        /* Cursor left a word        */
  605.         if (c_buffer_pos != ConsoleLineBuffer)
  606.         {
  607.         --c_buffer_pos;        /* Reposition on previous char    */
  608.  
  609.         while (isspace (*c_buffer_pos) &&
  610.                (c_buffer_pos != ConsoleLineBuffer))
  611.             --c_buffer_pos;
  612.  
  613.         while (!isspace (*c_buffer_pos) &&
  614.                (c_buffer_pos != ConsoleLineBuffer))
  615.             --c_buffer_pos;
  616.  
  617.         if (c_buffer_pos != ConsoleLineBuffer)
  618.             ++c_buffer_pos;
  619.         }
  620.  
  621.         else
  622.         RingWarningBell ();
  623.  
  624.         return FALSE;
  625.  
  626.     case KF_WORDRIGHT:        /* Cursor right a word        */
  627.         if (c_buffer_pos != EndOfCurrentLine)
  628.         {
  629.  
  630. /* Skip to the end of the current word */
  631.  
  632.         while (!isspace (*c_buffer_pos) &&
  633.                (c_buffer_pos != EndOfCurrentLine))
  634.             ++c_buffer_pos;
  635.  
  636. /* Skip over the white space */
  637.  
  638.         while (isspace (*c_buffer_pos) &&
  639.                (c_buffer_pos != EndOfCurrentLine))
  640.             ++c_buffer_pos;
  641.         }
  642.  
  643.         else
  644.         RingWarningBell ();
  645.  
  646.         return FALSE;
  647.  
  648.     case KF_START:            /* Cursor home            */
  649.         c_buffer_pos = ConsoleLineBuffer;
  650.         return FALSE;
  651.  
  652.     case KF_CLEAR:            /* Erase buffer            */
  653.         c_buffer_pos = ConsoleLineBuffer;
  654.  
  655.     case KF_FLUSH:            /* Flush to end            */
  656.         memset (c_buffer_pos, CHAR_SPACE, EndOfCurrentLine - c_buffer_pos);
  657.         EndOfCurrentLine = c_buffer_pos;
  658.         return TRUE;
  659.  
  660.     case KF_END:            /* Cursor end of command    */
  661.         if (*ConsoleLineBuffer == CHAR_HISTORY)
  662.         {
  663.         *EndOfCurrentLine = 0;
  664.         Process_History (2);
  665.         return TRUE;
  666.         }
  667.  
  668.         c_buffer_pos = EndOfCurrentLine;
  669.         return FALSE;
  670.  
  671.     case KF_INSERT:            /* Switch insert mode        */
  672.         InsertMode = C2bool (!InsertMode);
  673.         SetCursorShape (InsertMode);
  674.         return FALSE;
  675.  
  676.     case KF_CLEARSCREEN:        /* Clear the screen        */
  677.         return ClearScreen ();
  678.  
  679.     case KF_TRANSPOSE:        /* Transpose characters        */
  680.         if(c_buffer_pos == ConsoleLineBuffer)
  681.         return RingWarningBell ();
  682.  
  683.         if (c_buffer_pos == EndOfCurrentLine)
  684.         --c_buffer_pos;
  685.  
  686.         tmp = *(c_buffer_pos - 1);
  687.         *(c_buffer_pos - 1) = *c_buffer_pos;
  688.         *c_buffer_pos = tmp;
  689.  
  690.         if (c_buffer_pos != EndOfCurrentLine)
  691.         ++c_buffer_pos;
  692.  
  693.         return TRUE;
  694.  
  695.     case KF_QUOTE:            /* Quote characters        */
  696.         return ProcessAlphaNumericKey ((int)ReadKeyBoard ((unsigned char *)&tmp));
  697.  
  698. #if (OS_TYPE != OS_DOS)
  699.     case KF_JOBS:            /* Print Job Tree        */
  700.         fputchar (CHAR_NEW_LINE);
  701. #  if (OS_TYPE == OS_NT)
  702.         PrintJobs (TRUE);
  703. #  else
  704.         PrintProcessTree (getpid ());
  705. #  endif
  706.         OutputUserPrompt (LastUserPrompt);
  707.         StartCursorPosition = ReadCursorPosition ();
  708.         return TRUE;
  709. #endif
  710.  
  711.     case KF_DELETERIGHT:        /* Delete right character    */
  712.         if (c_buffer_pos == EndOfCurrentLine)
  713.         return FALSE;
  714.  
  715.         memcpy (c_buffer_pos, c_buffer_pos + 1,
  716.             EndOfCurrentLine - c_buffer_pos);
  717.  
  718.         if (EndOfCurrentLine == ConsoleLineBuffer)
  719.         {
  720.         RingWarningBell ();
  721.         return TRUE;
  722.         }
  723.  
  724.         if (--EndOfCurrentLine < c_buffer_pos)
  725.         --c_buffer_pos;
  726.  
  727.            return TRUE;
  728.  
  729.     case KF_DIRECTORY:        /* File name directory        */
  730.         fn_search = TRUE;
  731.  
  732.     case KF_COMPLETE:        /* File name completion        */
  733.     {
  734.         *EndOfCurrentLine = 0;
  735.         return CompleteFileName (c_buffer_pos, fn_search);
  736.     }
  737.  
  738.     case KF_DELETELEFT:        /* Delete left character    */
  739.         if (c_buffer_pos == ConsoleLineBuffer)
  740.         return RingWarningBell ();
  741.  
  742. /* Decrement current position */
  743.  
  744.         --c_buffer_pos;
  745.         memcpy (c_buffer_pos, c_buffer_pos + 1,
  746.             EndOfCurrentLine - c_buffer_pos);
  747.         --EndOfCurrentLine;
  748.         return TRUE;
  749.     }
  750.  
  751.     return FALSE;
  752. }
  753.  
  754. /* Set cursor shape */
  755.  
  756. #if (OS_TYPE == OS_OS2)
  757. void    SetCursorShape (bool mode)
  758. {
  759.     VIOCURSORINFO    viociCursor;
  760.  
  761.     VioGetCurType (&viociCursor, 0);
  762.  
  763.     if (mode && KF_List[KF_INSERTCURSOR].akey)
  764.     viociCursor.yStart = (USHORT)((KF_List[KF_HALFHEIGTH].akey
  765.                         ? (viociCursor.cEnd / 2) + 1 : 1));
  766.  
  767.     else
  768.     viociCursor.yStart = (USHORT)(viociCursor.cEnd - 1);
  769.  
  770.     VioSetCurType (&viociCursor, 0);
  771. }
  772. #endif
  773.  
  774. /* NT version */
  775.  
  776. #if (OS_TYPE == OS_NT)
  777. void    SetCursorShape (bool mode)
  778. {
  779.     CONSOLE_CURSOR_INFO        ConsoleCursorInfo;
  780.  
  781.     GetConsoleCursorInfo (NT_StdOut, &ConsoleCursorInfo);
  782.  
  783.     if (mode && KF_List[KF_INSERTCURSOR].akey)
  784.     ConsoleCursorInfo.dwSize = (KF_List[KF_HALFHEIGTH].akey ? 50 : 90);
  785.  
  786.     else
  787.     ConsoleCursorInfo.dwSize = 10;
  788.  
  789.     ConsoleCursorInfo.bVisible = TRUE;
  790.     SetConsoleCursorInfo (NT_StdOut, &ConsoleCursorInfo);
  791. }
  792. #endif
  793.  
  794. /* DOS version */
  795.  
  796. #if (OS_TYPE == OS_DOS)
  797. void    SetCursorShape (bool mode)
  798. {
  799.     union REGS        r;
  800.  
  801. /* Get the current cursor position to get the cursor lines */
  802.  
  803.     r.h.ah = 0x03;
  804.     SystemInterrupt (0x10, &r, &r);
  805.  
  806. /* Reset the type */
  807.  
  808.     r.h.ah = 0x01;
  809.  
  810.     if (mode && KF_List[KF_INSERTCURSOR].akey)
  811.     r.h.ch = (unsigned char)((KF_List[KF_HALFHEIGTH].akey
  812.                     ? (r.h.cl / 2) + 1 : 1));
  813.  
  814.     else
  815.     r.h.ch = (unsigned char)(r.h.cl - 1);
  816.  
  817.     SystemInterrupt (0x10, &r, &r);
  818. }
  819. #endif
  820.  
  821. /* UNIX version */
  822.  
  823. #if (OS_TYPE == OS_UNIX)
  824. void    SetCursorShape (bool mode)
  825. {
  826. }
  827. #endif
  828.  
  829. /*
  830.  * Read Cursor position
  831.  */
  832.  
  833. #if (OS_TYPE == OS_OS2)
  834. int    ReadCursorPosition (void)
  835. {
  836.     USHORT    usRow;
  837.     USHORT    usColumn;
  838.  
  839.     VioGetCurPos (&usRow, &usColumn, 0);
  840.     return (MaximumColumns * usRow) + usColumn;
  841. }
  842. #endif
  843.  
  844. /* NT Version */
  845.  
  846. #if (OS_TYPE == OS_NT)
  847. int    ReadCursorPosition (void)
  848. {
  849.     CONSOLE_SCREEN_BUFFER_INFO    CSI;
  850.  
  851.     GetConsoleScreenBufferInfo (NT_StdOut, &CSI);
  852.  
  853.     return (MaximumColumns * CSI.dwCursorPosition.Y) + CSI.dwCursorPosition.X;
  854. }
  855. #endif
  856.  
  857. /* DOS Version */
  858.  
  859. #if (OS_TYPE == OS_DOS) 
  860. int    ReadCursorPosition (void)
  861. {
  862.     union REGS    r;
  863.  
  864.     FlushStreams ();
  865.  
  866.     r.h.ah = 0x03;                /* Read cursor position    */
  867.     r.h.bh = 0;                    /* Page zero        */
  868.     SystemInterrupt (0x10, &r, &r);
  869.     return (r.h.dh * MaximumColumns) + r.h.dl;
  870. }
  871. #endif
  872.  
  873. /*
  874.  * Re-position the cursor
  875.  */
  876.  
  877. #if (OS_TYPE == OS_OS2)
  878. void    SetCursorPosition (int new)
  879. {
  880.     int        diff;
  881.     USHORT    usRow;
  882.     USHORT    usColumn;
  883.  
  884.     FlushStreams ();
  885.  
  886.     usRow = (USHORT)(new / MaximumColumns);
  887.     usColumn = (USHORT)(new % MaximumColumns);
  888.  
  889. /* Are we at the bottom of the page? */
  890.  
  891.     if (usRow >= (unsigned char)MaximumLines)
  892.     {
  893.     diff = usRow + 1 - MaximumLines;
  894.     usRow = (unsigned char)(MaximumLines - 1);
  895.     StartCursorPosition -= MaximumColumns * diff;
  896.     }
  897.  
  898.     VioSetCurPos (usRow, usColumn, 0);
  899. }
  900. #endif
  901.  
  902. /* NT Version */
  903.  
  904. #if (OS_TYPE == OS_NT)
  905. void    SetCursorPosition (int new)
  906. {
  907.     int        diff;
  908.     COORD    Cp;
  909.  
  910.     FlushStreams ();
  911.  
  912.     Cp.Y = (USHORT)(new / MaximumColumns);
  913.     Cp.X = (USHORT)(new % MaximumColumns);
  914.  
  915. /* Are we at the bottom of the page? */
  916.  
  917.     if (Cp.Y >= (unsigned char)MaximumLines)
  918.     {
  919.     diff = Cp.Y + 1 - MaximumLines;
  920.     Cp.Y = (unsigned char)(MaximumLines - 1);
  921.     StartCursorPosition -= MaximumColumns * diff;
  922.     }
  923.  
  924.     SetConsoleCursorPosition (NT_StdOut, Cp);
  925. }
  926. #endif
  927.  
  928. /* DOS Version */
  929.  
  930. #if (OS_TYPE == OS_DOS) 
  931. void    SetCursorPosition (int new)
  932. {
  933.     int        diff;
  934.     union REGS    r;
  935.  
  936.     FlushStreams ();
  937.  
  938.     r.h.ah = 0x02;                /* Set new position    */
  939.     r.h.bh = 0;                    /* Page zero        */
  940.     r.h.dh = (unsigned char)(new / MaximumColumns);
  941.     r.h.dl = (unsigned char)(new % MaximumColumns);
  942.  
  943. /* Are we at the bottom of the page? */
  944.  
  945.     if (r.h.dh >= (unsigned char)MaximumLines)
  946.     {
  947.     diff = r.h.dh + 1 - MaximumLines;
  948.     r.h.dh = (unsigned char)(MaximumLines - 1);
  949.     StartCursorPosition -= MaximumColumns * diff;
  950.     }
  951.  
  952.     SystemInterrupt (0x10, &r, &r);
  953. }
  954. #endif
  955.  
  956. /* Erase to end of line (avoid need for STUPID ansi.sys memory eater!) */
  957.  
  958. #if (OS_TYPE == OS_OS2) 
  959. static void F_LOCAL EraseToEndOfLine (void)
  960. {
  961.     BYTE    abCell[2];
  962.     USHORT    usRow;
  963.     USHORT    usColumn;
  964.     USHORT    cb = sizeof (abCell);
  965.  
  966.     FlushStreams ();
  967.  
  968. /* Read attribute under cursor */
  969.  
  970.     VioGetCurPos (&usRow, &usColumn, 0);
  971.     VioReadCellStr (abCell, &cb , usRow, usColumn, 0);
  972.  
  973.     abCell[0] = CHAR_SPACE;
  974.  
  975.     if (m_line < (int)usRow)
  976.     m_line = usRow;
  977.  
  978.     if ((cb = MaximumColumns - usColumn +
  979.         ((m_line - usRow) * MaximumColumns)) > 0)
  980.     VioWrtNCell (abCell, cb, usRow, usColumn, 0);
  981. }
  982. #endif
  983.  
  984. /* NT Version */
  985.  
  986. #if (OS_TYPE == OS_NT)
  987. static void F_LOCAL EraseToEndOfLine (void)
  988. {
  989.     WORD            Atts[2];
  990.     CONSOLE_SCREEN_BUFFER_INFO    CSI;
  991.     DWORD            ActionCount;
  992.     DWORD            cb;
  993.     WORD            *ostring;
  994.     DWORD            i;
  995.  
  996.     FlushStreams ();
  997.  
  998. /* Read attribute under cursor */
  999.  
  1000.     GetConsoleScreenBufferInfo (NT_StdOut, &CSI);
  1001.  
  1002.     ReadConsoleOutputAttribute (NT_StdOut, Atts, 1, CSI.dwCursorPosition,
  1003.                     &ActionCount);
  1004.  
  1005. /* How much to write ? */
  1006.  
  1007.     if (m_line < (int) CSI.dwCursorPosition.Y)
  1008.     m_line = CSI.dwCursorPosition.Y;
  1009.  
  1010. /* Write it.  What a pain!!! */
  1011.  
  1012.     if ((cb = MaximumColumns - CSI.dwCursorPosition.X +
  1013.         ((m_line - CSI.dwCursorPosition.Y) * MaximumColumns)) > 0)
  1014.     {
  1015.     ostring = (WORD *)AllocateMemoryCell (cb * sizeof (WORD));
  1016.     memset (ostring, CHAR_SPACE, cb);
  1017.  
  1018.     WriteConsoleOutputCharacter (NT_StdOut, (char *)ostring, cb,
  1019.                      CSI.dwCursorPosition, &ActionCount);
  1020.  
  1021. /* Set up attributes */
  1022.  
  1023.         for (i = 0; i < cb; i++)
  1024.         ostring[i] = Atts[0];
  1025.  
  1026.     WriteConsoleOutputAttribute (NT_StdOut, ostring, cb,
  1027.                      CSI.dwCursorPosition, &ActionCount);
  1028.         ReleaseMemoryCell (ostring);
  1029.     }
  1030. }
  1031. #endif
  1032.  
  1033. /* DOS Version */
  1034.  
  1035. #if (OS_TYPE == OS_DOS) 
  1036. static void F_LOCAL EraseToEndOfLine (void)
  1037. {
  1038.     union REGS        r;
  1039.     unsigned char    backg;
  1040.  
  1041.     FlushStreams ();
  1042.  
  1043. /* Get the background attribute of the cursor */
  1044.  
  1045.     r.h.ah = 0x08;
  1046.     r.h.bh = 0;
  1047.     SystemInterrupt (0x10, &r, &r);
  1048.     backg = (unsigned char)(r.h.ah & 0x07);
  1049.  
  1050.     r.h.ah = 0x03;
  1051.     r.h.bh = 0;
  1052.     SystemInterrupt (0x10, &r, &r);
  1053.  
  1054. /* Check that we use the correct m_line */
  1055.  
  1056.     if (m_line < (int)r.h.dh)
  1057.     m_line = r.h.dh;
  1058.  
  1059.     if ((r.x.REG_CX = MaximumColumns - r.h.dl +
  1060.               ((m_line - r.h.dh) * MaximumColumns)) > 0)
  1061.     {
  1062.     r.x.REG_AX = 0x0a20;
  1063.     r.x.REG_BX = backg;
  1064.     SystemInterrupt (0x10, &r, &r);
  1065.     }
  1066. }
  1067. #endif
  1068.  
  1069. /* DOS Version */
  1070.  
  1071. #if (OS_TYPE == OS_UNIX) 
  1072. static void F_LOCAL EraseToEndOfLine (void)
  1073. {
  1074.     fputs ("UNIX: EraseToEndOfLine NI\n", stderr);
  1075. }
  1076. #endif
  1077.  
  1078. /*
  1079.  * Generate the new cursor position
  1080.  */
  1081.  
  1082. static void F_LOCAL GenerateNewCursorPosition (void)
  1083. {
  1084.     char    *cp = ConsoleLineBuffer - 1;
  1085.     int        off = StartCursorPosition;
  1086.  
  1087. /* Search to current position */
  1088.  
  1089.     while (++cp != c_buffer_pos)
  1090.     {
  1091.     if (*cp == CHAR_TAB)
  1092.         while ((++off) % 8);
  1093.  
  1094.     else
  1095.         off += (iscntrl (*cp)) ? 2 : 1;
  1096.     }
  1097.  
  1098. /* Position the cursor */
  1099.  
  1100.     SetCursorPosition (off);
  1101. }
  1102.  
  1103. /* Redisplay the current line */
  1104.  
  1105. static void F_LOCAL ReDisplayInputLine (void)
  1106. {
  1107. /* Reposition to start of line */
  1108.  
  1109.     SetCursorPosition (StartCursorPosition);
  1110.  
  1111. /* Output the line */
  1112.  
  1113.     *EndOfCurrentLine = 0;
  1114.     DisplayLineWithControl (ConsoleLineBuffer);
  1115.  
  1116.     if ((m_line = ((StartCursorPosition + MaxLength) / MaximumColumns) + 1) >=
  1117.     MaximumLines)
  1118.     m_line = MaximumLines - 1;
  1119.  
  1120.     EraseToEndOfLine ();        /* clear to end of line    */
  1121.     MaxLength = EndOfCurrentLine - ConsoleLineBuffer;
  1122. }
  1123.  
  1124. /* Process history command
  1125.  *
  1126.  * -1: Previous command
  1127.  *  1: Next command
  1128.  *  0: Current command
  1129.  *  2: Current command with no options processing
  1130.  */
  1131.  
  1132. static bool F_LOCAL Process_History (int direction)
  1133. {
  1134.     char    *optionals = null;
  1135.  
  1136.     c_buffer_pos = ConsoleLineBuffer;
  1137.     EndOfCurrentLine = ConsoleLineBuffer;
  1138.     c_history += (direction == 2) ? 0 : direction;
  1139.  
  1140.     switch (direction)
  1141.     {
  1142.     case -1:            /* Move up one line        */
  1143.         if (c_history < 0)
  1144.         {
  1145.         c_history = -1;
  1146.         return ReStartInput (No_prehistory);
  1147.         }
  1148.  
  1149.         break;
  1150.  
  1151.     case 1:                /* Move to next history line    */
  1152.         if (c_history >= l_history)
  1153.         {
  1154.         c_history = l_history;
  1155.         return ReStartInput (No_posthistory);
  1156.         }
  1157.  
  1158.         break;
  1159.  
  1160.     case 0:                /* Check out ConsoleLineBuffer    */
  1161.         optionals = ConsoleLineBuffer;/* Are there any additions to    */
  1162.                     /* the history line        */
  1163.  
  1164. /* Find the end of the first part */
  1165.  
  1166.         while (!isspace (*optionals) && *optionals)
  1167.         {
  1168.         if (*optionals == CHAR_HISTORY)
  1169.         {
  1170.  
  1171. /* Terminate at !! */
  1172.  
  1173.             if (*(optionals + 1) == CHAR_HISTORY)
  1174.             {
  1175.             optionals += 2;
  1176.             break;
  1177.             }
  1178.  
  1179. /* Terminate at a numeric value */
  1180.  
  1181.             else if (isdigit (*(optionals + 1)) ||
  1182.                  (*(optionals + 1) == '-'))
  1183.             {
  1184.             optionals += 2;
  1185.             while (isdigit (*optionals))
  1186.                 ++optionals;
  1187.  
  1188.             break;
  1189.             }
  1190.         }
  1191.  
  1192.         ++optionals;
  1193.         }
  1194.  
  1195. /* Copy selected item into line buffer */
  1196.  
  1197.     case 2:
  1198.         M_length = (optionals == null) ? strlen (ConsoleLineBuffer) - 1
  1199.                        : optionals - ConsoleLineBuffer - 1;
  1200.  
  1201.         if (!ScanHistory ())
  1202.         return FALSE;
  1203.  
  1204.         break;
  1205.     }
  1206.  
  1207.     return UpdateConsoleInputLine (optionals);
  1208. }
  1209.  
  1210. /* Ok c_history points to the new line.  Move optionals after history
  1211.  * and the copy in history and add a space
  1212.  */
  1213.  
  1214. static bool F_LOCAL UpdateConsoleInputLine (char *optionals)
  1215. {
  1216.     int        opt_len;
  1217.  
  1218.     EndOfCurrentLine = &ConsoleLineBuffer[strlen (cmd_history[c_history].command)];
  1219.  
  1220.     if ((EndOfCurrentLine - ConsoleLineBuffer +
  1221.      (opt_len = strlen (optionals)) + 1) >= LINE_MAX)
  1222.     return ReStartInput (History_2long);
  1223.  
  1224.     if (EndOfCurrentLine > optionals)
  1225.     memrcpy (EndOfCurrentLine + opt_len, optionals + opt_len, opt_len + 1);
  1226.  
  1227.     else
  1228.     strcpy (EndOfCurrentLine, optionals);
  1229.  
  1230.     strncpy (ConsoleLineBuffer, cmd_history[c_history].command,
  1231.          (EndOfCurrentLine - ConsoleLineBuffer));
  1232.     EndOfCurrentLine = &ConsoleLineBuffer[strlen (ConsoleLineBuffer)];
  1233.     c_buffer_pos = EndOfCurrentLine;
  1234.     return TRUE;
  1235. }
  1236.  
  1237. /* Scan the line buffer for a history match */
  1238.  
  1239. static bool F_LOCAL ScanHistory (void)
  1240. {
  1241.     char    *cp = ConsoleLineBuffer + 1;
  1242.     char    *ep;
  1243.     int        i = (int)strtol (cp, &ep, 10);
  1244.  
  1245. /* Get the previous command ? (single ! or double !!) */
  1246.  
  1247.     if ((M_length == 0) || (*cp == CHAR_HISTORY))
  1248.     {
  1249.     if (c_history >= l_history)
  1250.         c_history = l_history - 1;
  1251.  
  1252.     if (c_history < 0)
  1253.         return ReStartInput (No_prehistory);
  1254.  
  1255.     return TRUE;
  1256.     }
  1257.  
  1258. /* Request for special history number item.  Check History file empty */
  1259.  
  1260.     if (l_history == 0)
  1261.     return ReStartInput (No_MatchHistory);
  1262.  
  1263. /* Check for number */
  1264.  
  1265.     if ((*ConsoleLineBuffer == CHAR_HISTORY) && (ep > cp) && M_length)
  1266.     {
  1267.     M_length = -1;
  1268.  
  1269.     for (c_history = l_history - 1;
  1270.         (c_history >= 0) && (cmd_history[c_history].number != i);
  1271.         --c_history)
  1272.         continue;
  1273.     }
  1274.  
  1275. /* No - scan for a match */
  1276.  
  1277.     else
  1278.     {
  1279.     for (c_history = l_history - 1;
  1280.          (c_history >= 0) &&
  1281.          (strncmp (cp, cmd_history[c_history].command, M_length) != 0);
  1282.          --c_history)
  1283.         continue;
  1284.     }
  1285.  
  1286. /* Anything found ? */
  1287.  
  1288.     if (c_history == -1)
  1289.     {
  1290.     c_history = l_history - 1;
  1291.     return ReStartInput (No_MatchHistory);
  1292.     }
  1293.  
  1294.     return TRUE;
  1295. }
  1296.  
  1297. /*
  1298.  * Get record associated with event
  1299.  */
  1300.  
  1301. char    *GetHistoryRecord (int event)
  1302. {
  1303.     int        i = l_history - 1;
  1304.  
  1305.     while (i >= 0)
  1306.     {
  1307.         if (cmd_history[i].number == event)
  1308.         return cmd_history[i].command;
  1309.  
  1310.     --i;
  1311.     }
  1312.  
  1313.     return (char *)NULL;
  1314. }
  1315.  
  1316. /*
  1317.  * Scan back or forward from current history
  1318.  */
  1319.  
  1320. static void F_LOCAL PageHistoryRecord (int direction)
  1321. {
  1322.     c_buffer_pos = ConsoleLineBuffer;
  1323.     EndOfCurrentLine = ConsoleLineBuffer;
  1324.  
  1325.     if (l_history == 0)
  1326.     {
  1327.     ReStartInput (No_MatchHistory);
  1328.     return;
  1329.     }
  1330.  
  1331. /* scan for a match */
  1332.  
  1333.     while (((c_history += direction) >= 0) && (c_history != l_history) &&
  1334.        (strncmp (ConsoleLineBuffer, cmd_history[c_history].command,
  1335.              M_length) != 0))
  1336.     continue;
  1337.  
  1338. /* Anything found ? */
  1339.  
  1340.     if ((c_history < 0) || (c_history >= l_history))
  1341.     {
  1342.     c_history = l_history - 1;
  1343.     ReStartInput (No_MatchHistory);
  1344.     }
  1345.  
  1346.     else
  1347.     UpdateConsoleInputLine (null);
  1348. }
  1349.  
  1350. /* Load history file */
  1351.  
  1352. void LoadHistory (void)
  1353. {
  1354.     FILE        *fp;
  1355.     char        *cp;
  1356.     int            i = 0;
  1357.     bool        Append = FALSE;
  1358.  
  1359. /* Initialise history array */
  1360.  
  1361.     c_history = -1;            /* Current entry        */
  1362.     l_history = 0;            /* End of history array        */
  1363.  
  1364.     if (GetVariableAsString (HistoryFileVariable, FALSE) == null)
  1365.     {
  1366.     SetVariableFromString (HistoryFileVariable,
  1367.                    (cp = BuildFileName ("history.sh")));
  1368.     ReleaseMemoryCell ((void *)cp);
  1369.     }
  1370.  
  1371.     if (GetVariableAsString (HistorySizeVariable, FALSE) == null)
  1372.     SetVariableFromNumeric (HistorySizeVariable, 100L);
  1373.  
  1374.     if ((fp = OpenHistoryFile (sOpenReadMode)) == (FILE *)NULL)
  1375.     return;
  1376.  
  1377. /* Read in file */
  1378.  
  1379.     cp = ConsoleLineBuffer;
  1380.  
  1381.     while ((i = fgetc (fp)) != EOF)
  1382.     {
  1383.     if (i == 0)
  1384.     {
  1385.         *cp = 0;
  1386.         cp = ConsoleLineBuffer;
  1387.         AddHistory (Append);
  1388.         Append = FALSE;
  1389.     }
  1390.  
  1391.     else if (i == CHAR_NEW_LINE)
  1392.     {
  1393.         *cp = 0;
  1394.         cp = ConsoleLineBuffer;
  1395.         AddHistory (Append);
  1396.         Append = TRUE;
  1397.     }
  1398.  
  1399.     else if ((cp - ConsoleLineBuffer) < LINE_MAX - 2)
  1400.         *(cp++) = (char)i;
  1401.     }
  1402.  
  1403.     CloseFile (fp);
  1404. }
  1405.  
  1406. /* Open the history file */
  1407.  
  1408. static FILE * F_LOCAL OpenHistoryFile (char *mode)
  1409. {
  1410.     char    *name;
  1411.  
  1412.     if (!HistoryEnabled)
  1413.     return (FILE *)NULL;
  1414.  
  1415.     name = CheckDOSFileName (GetVariableAsString (HistoryFileVariable, FALSE));
  1416.     return FOpenFile (name, mode);
  1417. }
  1418.  
  1419. /* Add entry to history file */
  1420.  
  1421. void AddHistory (bool AppendToLast)
  1422. {
  1423.     char        *cp;
  1424.     struct cmd_history    *cmd;
  1425.     size_t        Len;
  1426.     int            HistorySize;
  1427.  
  1428. /* Clean up console buffer */
  1429.  
  1430.     CleanUpBuffer (strlen (ConsoleLineBuffer), ConsoleLineBuffer, GetEOFKey ());
  1431.  
  1432. /*
  1433.  * Ignore if no history or blank line
  1434.  */
  1435.  
  1436.     if ((!HistoryEnabled) || (strlen (ConsoleLineBuffer) == 0))
  1437.     return;
  1438.  
  1439. /* Has the size changed ? */
  1440.  
  1441.     HistorySize = (int)GetVariableAsNumeric (HistorySizeVariable);
  1442.  
  1443.     if (HistorySize != CurrentHistorySize)
  1444.     {
  1445.  
  1446. /* Zero - empty history */
  1447.  
  1448.     if (!HistorySize)
  1449.         ClearHistory ();
  1450.  
  1451. /* Allocate a new buffer */
  1452.  
  1453.     else if ((cmd = (struct cmd_history *)GetAllocatedSpace
  1454.                 (sizeof (struct cmd_history) * HistorySize)) ==
  1455.            (struct cmd_history *)NULL)
  1456.         /* DO NOTHING IF NO MEMORY */;
  1457.  
  1458. /* If new buffer is bigger, copy old to new and release */
  1459.  
  1460.     else if ((HistorySize > CurrentHistorySize) ||
  1461.          (l_history < HistorySize))
  1462.     {
  1463.         if (cmd_history != (struct cmd_history *)NULL)
  1464.         {
  1465.         int    Clen;
  1466.  
  1467. /* Calculate the length to copy */
  1468.  
  1469.         Clen = (HistorySize > CurrentHistorySize)
  1470.             ? CurrentHistorySize : l_history;
  1471.  
  1472.         memcpy (cmd, cmd_history,
  1473.             sizeof (struct cmd_history) * Clen);
  1474.  
  1475. /* Set up new values */
  1476.  
  1477.         ReleaseMemoryCell (cmd_history);
  1478.         }
  1479.  
  1480.         CurrentHistorySize = HistorySize;
  1481.         SetMemoryAreaNumber ((void *)(cmd_history = cmd), 0);
  1482.     }
  1483.  
  1484. /* Less space is available, copy reduced area and update entry numbers */
  1485.  
  1486.     else
  1487.     {
  1488.         int        i = (CurrentHistorySize - HistorySize);
  1489.  
  1490. /* Free entries at bottom */
  1491.  
  1492.         for (Len = 0; (Len < (size_t)i) && (Len < (size_t)l_history); Len++)
  1493.         ReleaseCommandMemory (&cmd_history[Len]);
  1494.  
  1495. /* Transfer entries at top */
  1496.  
  1497.         memcpy (cmd, &cmd_history[i],
  1498.             sizeof (struct cmd_history) * HistorySize);
  1499.  
  1500. /* Update things */
  1501.  
  1502.         if ((c_history -= i) < -1)
  1503.         c_history = -1;
  1504.  
  1505.         if ((l_history -= i) < 0)
  1506.         l_history = 0;
  1507.  
  1508. /* Set up new values */
  1509.  
  1510.         ReleaseMemoryCell (cmd_history);
  1511.         CurrentHistorySize = HistorySize;
  1512.         SetMemoryAreaNumber ((void *)(cmd_history = cmd), 0);
  1513.     }
  1514.     }
  1515.  
  1516. /* If there is no history space - return */
  1517.  
  1518.     if (!CurrentHistorySize)
  1519.     return;
  1520.  
  1521. /* If the array is full, remove the last item */
  1522.  
  1523.     if (l_history == CurrentHistorySize)
  1524.     {
  1525.     ReleaseCommandMemory (&cmd_history[0]);
  1526.  
  1527.     --l_history;
  1528.     memcpy (&cmd_history[0], &cmd_history[1],
  1529.         sizeof (struct cmd_history) * (CurrentHistorySize - 1));
  1530.     }
  1531.  
  1532. /* Save the string.  Is this a PS2 prompt */
  1533.  
  1534.     if ((AppendToLast) && l_history)
  1535.     {
  1536.     cmd = &cmd_history[l_history - 1];
  1537.  
  1538. /* Check length */
  1539.  
  1540.     if ((Len = strlen (cmd->command) + strlen (ConsoleLineBuffer) + 2)
  1541.         >= LINE_MAX)
  1542.     {
  1543.         fprintf (stderr, BasicErrorMessage, LIT_history, History_2long);
  1544.         return;
  1545.     }
  1546.  
  1547. /* Append to buffer, reallocate to new length */
  1548.  
  1549.     if ((cp = GetAllocatedSpace (Len)) == (char *)NULL)
  1550.         return;
  1551.  
  1552.     sprintf (cp, "%s\n%s", cmd->command, ConsoleLineBuffer);
  1553.  
  1554.     ReleaseCommandMemory (cmd);
  1555.     cmd->command = cp;
  1556.     SetMemoryAreaNumber ((void *)cp, 0);
  1557.     }
  1558.  
  1559. /* Save the command line */
  1560.  
  1561.     else
  1562.     {
  1563.     Current_Event = GetLastHistoryEvent ();
  1564.     cmd_history[l_history].number = Current_Event;
  1565.  
  1566.     cmd_history[l_history].command = StringSave (ConsoleLineBuffer);
  1567.     c_history = ++l_history;
  1568.     }
  1569. }
  1570.  
  1571. /*
  1572.  * Dump history to file
  1573.  */
  1574.  
  1575. void DumpHistory (void)
  1576. {
  1577.     struct cmd_history    *cp = cmd_history;
  1578.     FILE        *fp;
  1579.     int            i;
  1580.  
  1581. /* If history is not enabled or we can't open the file, give up */
  1582.  
  1583.     if ((!HistoryEnabled) ||
  1584.     ((fp = OpenHistoryFile (sOpenWriteMode)) == (FILE *)NULL))
  1585.     return;
  1586.  
  1587. /* Write history as a null terminated record */
  1588.  
  1589.     for (i = 0; i < l_history; ++cp, ++i)
  1590.     {
  1591.         fputs (cp->command, fp);
  1592.     fputc (0, fp);
  1593.     }
  1594.  
  1595.     CloseFile (fp);
  1596. }
  1597.  
  1598. /* Clear out history */
  1599.  
  1600. void ClearHistory (void)
  1601. {
  1602.     int            i;
  1603.     struct cmd_history    *cp = cmd_history;
  1604.  
  1605. /* Release the entries */
  1606.  
  1607.     for (i = 0; i < l_history; ++cp, ++i)
  1608.     ReleaseCommandMemory (cp);
  1609.  
  1610.     ReleaseMemoryCell (cmd_history);
  1611.  
  1612. /* Reset data information */
  1613.  
  1614.     c_history = -1;            /* Current entry        */
  1615.     l_history = 0;            /* End of history array        */
  1616.     Current_Event = 0;
  1617.     CurrentHistorySize = 0;
  1618.     cmd_history = (struct cmd_history *)NULL;
  1619. }
  1620.  
  1621. /* Output warning message and prompt */
  1622.  
  1623. static bool F_LOCAL ReStartInput (char *cp)
  1624. {
  1625.     if (cp != (char *)NULL)
  1626.     {
  1627.     if (!IS_Console (1) ||
  1628.         (strlen (ConsoleLineBuffer) && (StartCursorPosition != -1)))
  1629.         feputc (CHAR_NEW_LINE);
  1630.  
  1631.     PrintWarningMessage (BasicErrorMessage, LIT_history, cp);
  1632.  
  1633.     if (IS_Console (1))
  1634.         EraseToEndOfLine ();
  1635.  
  1636.     fputchar (CHAR_NEW_LINE);
  1637.     }
  1638.  
  1639.     OutputUserPrompt (LastUserPrompt);
  1640.  
  1641. /* Re-initialise */
  1642.  
  1643.     InitialiseInput (InsertMode);
  1644.     return FALSE;
  1645. }
  1646.  
  1647. /* Copy backwards */
  1648.  
  1649. static void F_LOCAL memrcpy (char *sp1, char *sp, int cnt)
  1650. {
  1651.     while (cnt--)
  1652.     *(sp1--) = *(sp--);
  1653. }
  1654.  
  1655. /* Complete Filename functions */
  1656.  
  1657. static bool F_LOCAL CompleteFileName (char *InsertPosition, bool Searching)
  1658. {
  1659.     int            NumberOfMatches = 0;
  1660.     char        *SearchString = null;
  1661.     char        *NameStart = InsertPosition;
  1662.     char        *StartDirInCLB;
  1663.     size_t        MatchStringLen = 0;
  1664.     char        *cp;
  1665.     int            i;
  1666.     size_t        maxi;
  1667.     bool        InsertSpace = TRUE;
  1668.     char        **FileList;
  1669.  
  1670. /* Space or at start of line - use NULL file name */
  1671.  
  1672.     if ((NameStart != ConsoleLineBuffer) && isspace (*NameStart) &&
  1673.     !isspace (*(NameStart - 1)))
  1674.     {
  1675.     --NameStart;
  1676.     InsertSpace = FALSE;
  1677.     }
  1678.  
  1679.     if (!isspace (*NameStart))
  1680.     {
  1681.     while (!isspace (*NameStart) && (NameStart != ConsoleLineBuffer))
  1682.         --NameStart;
  1683.  
  1684.     if (isspace (*NameStart))
  1685.         ++NameStart;
  1686.  
  1687.     MatchStringLen = InsertPosition - NameStart;
  1688.  
  1689.     if ((SearchString = AllocateMemoryCell (MatchStringLen + 1)) ==
  1690.                         (char *)NULL)
  1691.         return RingWarningBell ();
  1692.  
  1693.     memcpy (SearchString, NameStart, MatchStringLen);
  1694.     }
  1695.  
  1696. /* Find the directory name */
  1697.  
  1698.     if ((cp = FindLastPathCharacter (SearchString)) != (char *)NULL)
  1699.     StartDirInCLB = NameStart + (int)(cp - SearchString + 1);
  1700.  
  1701. /* No directory flag - Drive specifier? */
  1702.  
  1703.     else if ((strlen (SearchString) > (size_t)1) &&
  1704.          IsDriveCharacter (*(SearchString + 1)))
  1705.     StartDirInCLB = NameStart + 2;
  1706.  
  1707. /* No drive specifier */
  1708.  
  1709.     else
  1710.     StartDirInCLB = NameStart;
  1711.  
  1712.     FileList = BuildCompletionList (SearchString, strlen (SearchString),
  1713.                     &NumberOfMatches, FALSE);
  1714.  
  1715.     if (SearchString != null)
  1716.         ReleaseMemoryCell ((void *)SearchString);
  1717.  
  1718. /* If there are no matches, Just ring the bell */
  1719.  
  1720.     if (FileList == (char **)NULL)
  1721.     return RingWarningBell ();
  1722.  
  1723. /* At this point, we have some data.  If we are searching, sort the
  1724.  * filenames and display them.  Remember to release the memory allocated for
  1725.  * the word block and its entries.
  1726.  */
  1727.  
  1728.     if (Searching)
  1729.     {
  1730.  
  1731. /* Sort the file names and display them */
  1732.  
  1733.     qsort (&FileList[0], NumberOfMatches, sizeof (char *), SortCompare);
  1734.  
  1735. /* Display. */
  1736.  
  1737.     fputchar (CHAR_NEW_LINE);
  1738.     PrintAList (NumberOfMatches, FileList);
  1739.  
  1740. /* Release memory */
  1741.  
  1742.     ReleaseAList (FileList);
  1743.  
  1744. /* Redraw current line */
  1745.  
  1746.     OutputUserPrompt (LastUserPrompt);
  1747.     StartCursorPosition = ReadCursorPosition ();
  1748.     return TRUE;
  1749.     }
  1750.  
  1751. /* OK, we are completing. Get the common part of the filename list */
  1752.  
  1753.     maxi = GetCommonPartOfFileList (FileList);
  1754.  
  1755. /* If the file name is length matches the search length, there are no unique
  1756.  * parts to the filenames in the directory.  Just ring the bell and return.
  1757.  */
  1758.  
  1759.     if ((maxi == MatchStringLen) && (NumberOfMatches > 1))
  1760.     {
  1761.     ReleaseAList (FileList);
  1762.     return RingWarningBell ();
  1763.     }
  1764.  
  1765. /* So, at this point, we are completing and have something to append.  Check
  1766.  * that the line is not too long and if there is an end bit, we can save a
  1767.  * copy of it.
  1768.  */
  1769.  
  1770. /* Insert after spaces */
  1771.  
  1772.     if (InsertSpace && isspace (*InsertPosition) &&
  1773.     (InsertPosition != ConsoleLineBuffer))
  1774.     {
  1775.     ++StartDirInCLB;
  1776.     ++InsertPosition;
  1777.     }
  1778.  
  1779.     cp = null;
  1780.  
  1781.     if (((strlen (InsertPosition) + maxi +
  1782.              (StartDirInCLB - ConsoleLineBuffer) + 3) >= LINE_MAX) ||
  1783.     (strlen (InsertPosition) &&
  1784.      ((cp = StringCopy (InsertPosition)) == null)))
  1785.     {
  1786.     ReleaseAList (FileList);
  1787.     return RingWarningBell ();
  1788.     }
  1789.  
  1790. /* Append the new end of line bits */
  1791.  
  1792.     strcpy (StartDirInCLB, *FileList);
  1793.     strcpy (&StartDirInCLB[i = strlen (StartDirInCLB)], " ");
  1794.  
  1795. /* Save the current position */
  1796.  
  1797.     c_buffer_pos = &ConsoleLineBuffer[strlen (ConsoleLineBuffer)];
  1798.  
  1799. /* If we found only 1 and its a directory, append a d sep */
  1800.  
  1801.     if ((NumberOfMatches == 1) && IsDirectory (NameStart))
  1802.     {
  1803.     StartDirInCLB[i] = CHAR_UNIX_DIRECTORY;
  1804.     strcpy (c_buffer_pos, cp);
  1805.     }
  1806.  
  1807. /* If multiple matches, position at filename and not original position */
  1808.  
  1809.     else
  1810.     {
  1811.     if (isspace (*cp))
  1812.         --c_buffer_pos;
  1813.  
  1814.     strcpy (c_buffer_pos, cp);
  1815.  
  1816.     if ((NumberOfMatches > 1) && !isspace (*cp))
  1817.         --c_buffer_pos;
  1818.     }
  1819.  
  1820. /* Release the saved buffer and reset end of line pointer */
  1821.  
  1822.     if (cp != null)
  1823.     ReleaseMemoryCell ((void *)cp);
  1824.  
  1825.     ReleaseAList (FileList);
  1826.     EndOfCurrentLine = &ConsoleLineBuffer[strlen (ConsoleLineBuffer)];
  1827.  
  1828. /* Beep if more than one */
  1829.  
  1830.     if (NumberOfMatches > 1)
  1831.     RingWarningBell ();
  1832.  
  1833.     return TRUE;
  1834. }
  1835.  
  1836. /* Initialise input */
  1837.  
  1838. static void F_LOCAL InitialiseInput (bool im)
  1839. {
  1840.     c_buffer_pos = ConsoleLineBuffer;    /* Initialise            */
  1841.     EndOfCurrentLine = ConsoleLineBuffer;
  1842.     SetCursorShape (InsertMode = im);
  1843.     M_length = -1;
  1844.  
  1845. /* Reset max line length */
  1846.  
  1847.     MaxLength = 0;
  1848.     OldMaxLength = 0;
  1849.  
  1850. /* Save the cursor position */
  1851.  
  1852.     if (IS_Console (1))
  1853.     StartCursorPosition = ReadCursorPosition ();
  1854. }
  1855.  
  1856. /* Configure Keyboard I/O */
  1857.  
  1858. void Configure_Keys (void)
  1859. {
  1860.     char        *cp;            /* Line pointers    */
  1861.     int            i, fval, cval;
  1862.     int            nFields;
  1863.     LineFields        LF;
  1864.     long        value;
  1865.  
  1866. /* Get some memory for the input line and the file name */
  1867.  
  1868.     if ((LF.LineLength = strlen (cp = GetVariableAsString (ShellVariableName,
  1869.                                   FALSE)) + 5) < 200)
  1870.     LF.LineLength = 200;
  1871.  
  1872.     if ((LF.Line = AllocateMemoryCell (LF.LineLength)) == (char *)NULL)
  1873.     return;
  1874.  
  1875.     strcpy (LF.Line, cp);
  1876.  
  1877. /* Find the .exe in the name */
  1878.  
  1879.     if ((cp = FindLastPathCharacter (LF.Line)) != (char *)NULL)
  1880.     ++cp;
  1881.  
  1882.     else
  1883.     cp = LF.Line;
  1884.  
  1885.     if ((cp = strrchr (cp, CHAR_PERIOD)) == (char *)NULL)
  1886.     cp = &LF.Line[strlen (LF.Line)];
  1887.  
  1888.     strcpy (cp, ".ini");
  1889.  
  1890.     if ((LF.FP = FOpenFile (CheckDOSFileName (LF.Line),
  1891.                     sOpenReadMode)) == (FILE *)NULL)
  1892.     {
  1893.     ReleaseMemoryCell ((void *)LF.Line);
  1894.     return;
  1895.     }
  1896.  
  1897. /* Initialise the internal buffer */
  1898.  
  1899.     LF.Fields = (Word_B *)NULL;
  1900.  
  1901. /* Scan for the file */
  1902.  
  1903.     while ((nFields = ExtractFieldsFromLine (&LF)) != -1)
  1904.     {
  1905.         if (nFields < 2)
  1906.             continue;
  1907.  
  1908. /* Look up the keyword name */
  1909.  
  1910.     for (i = 0;
  1911.          (i < KF_LENGTH) && (stricmp (LF.Fields->w_words[0],
  1912.                  KF_List[i].kf_name) != 0);
  1913.          ++i)
  1914.         continue;
  1915.  
  1916. /* Ignore no matches */
  1917.  
  1918.     if (i == KF_LENGTH)
  1919.         continue;
  1920.  
  1921. /* Get the value of the second field - must be numeric */
  1922.  
  1923.     cval = 0;
  1924.  
  1925.     if (!ConvertNumericValue (LF.Fields->w_words[1], &value, 0))
  1926.         continue;
  1927.  
  1928.     fval = (int)value;
  1929.  
  1930. /* Get the value of the third field, if it exists - must be numeric */
  1931.  
  1932.     if (nFields == 3)
  1933.     {
  1934.         if (!ConvertNumericValue (LF.Fields->w_words[2], &value, 0))
  1935.         continue;
  1936.  
  1937.         cval = (int)value;
  1938.     }
  1939.  
  1940. /* OK we have a valid value, save it */
  1941.  
  1942.     KF_List[i].akey = (char)fval;
  1943.     KF_List[i].fkey = (char)cval;
  1944.     }
  1945.  
  1946.     ReleaseMemoryCell ((void *)LF.Line);
  1947. }
  1948.  
  1949. /* Check cursor is in column zero */
  1950.  
  1951. #if (OS_TYPE == OS_OS2)
  1952. void PositionCursorInColumnZero (void)
  1953. {
  1954.     BYTE        abCell[2];
  1955.     USHORT        usRow;
  1956.     USHORT        usColumn;
  1957.     USHORT        cb = sizeof (abCell);
  1958.  
  1959. /* Get screen infor and cursor position */
  1960.  
  1961.     GetScreenParameters ();
  1962.     StartCursorPosition = ReadCursorPosition ();
  1963.  
  1964.     VioGetCurPos (&usRow, &usColumn, 0);
  1965.     VioReadCellStr (abCell, &cb , usRow, usColumn, 0);
  1966.  
  1967.     if ((StartCursorPosition % MaximumColumns) || (abCell[0] != CHAR_SPACE))
  1968.     fputchar (CHAR_NEW_LINE);
  1969. }
  1970. #endif
  1971.  
  1972. /* NT Version */
  1973.  
  1974. #if (OS_TYPE == OS_NT)
  1975. void PositionCursorInColumnZero (void)
  1976. {
  1977.     char            abCell[2];
  1978.     CONSOLE_SCREEN_BUFFER_INFO    CSI;
  1979.     DWORD            ActionCount;
  1980.  
  1981. /* Get screen infor and cursor position */
  1982.  
  1983.     GetScreenParameters ();
  1984.     StartCursorPosition = ReadCursorPosition ();
  1985.  
  1986.     GetConsoleScreenBufferInfo (NT_StdOut, &CSI);
  1987.     ReadConsoleOutputCharacter (NT_StdOut, abCell, 1, CSI.dwCursorPosition,
  1988.                     &ActionCount);
  1989.  
  1990.     if ((StartCursorPosition % MaximumColumns) || (*abCell != CHAR_SPACE))
  1991.     fputchar (CHAR_NEW_LINE);
  1992. }
  1993. #endif
  1994.  
  1995. /* DOS Version */
  1996.  
  1997. #if (OS_TYPE == OS_DOS) 
  1998. void PositionCursorInColumnZero (void)
  1999. {
  2000.     union REGS        r;
  2001.  
  2002. /* Get screen infor and cursor position */
  2003.  
  2004.     GetScreenParameters ();
  2005.     StartCursorPosition = ReadCursorPosition ();
  2006.  
  2007.     r.h.ah = 0x08;
  2008.     r.h.bh = 0x00;
  2009.     SystemInterrupt (0x10, &r, &r);
  2010.  
  2011.     if ((StartCursorPosition % MaximumColumns) || (r.h.al != CHAR_SPACE))
  2012.     fputchar (CHAR_NEW_LINE);
  2013. }
  2014. #endif
  2015.  
  2016. /*
  2017.  * Get screen parameters
  2018.  */
  2019.  
  2020. #if (OS_TYPE == OS_OS2) 
  2021. void    GetScreenParameters (void)
  2022. {
  2023.     VIOMODEINFO        viomi;
  2024.  
  2025.     viomi.cb = sizeof(viomi);
  2026.  
  2027.     VioGetMode (&viomi, 0);
  2028.     MaximumColumns = viomi.col;
  2029.     MaximumLines = viomi.row;
  2030.  
  2031. /* Set up LINES and COLUMNS variables */
  2032.  
  2033.     SetVariableFromNumeric (LIT_LINES, (long)MaximumLines);
  2034.     SetVariableFromNumeric (LIT_COLUMNS, (long)MaximumColumns);
  2035. }
  2036. #endif
  2037.  
  2038. /* NT Version */
  2039.  
  2040. #if (OS_TYPE == OS_NT) 
  2041. void    GetScreenParameters (void)
  2042. {
  2043.     CONSOLE_SCREEN_BUFFER_INFO    CSI;
  2044.  
  2045.     NT_StdOut = GetStdHandle (STD_OUTPUT_HANDLE);
  2046.     GetConsoleScreenBufferInfo (NT_StdOut, &CSI);
  2047.  
  2048.     MaximumColumns = CSI.dwMaximumWindowSize.X;
  2049.     MaximumLines = CSI.dwMaximumWindowSize.Y;
  2050.  
  2051. /* Set up LINES and COLUMNS variables */
  2052.  
  2053.     SetVariableFromNumeric (LIT_LINES, (long)MaximumLines);
  2054.     SetVariableFromNumeric (LIT_COLUMNS, (long)MaximumColumns);
  2055. }
  2056. #endif
  2057.  
  2058. /* DOS version */
  2059.  
  2060. #if (OS_TYPE == OS_DOS) 
  2061. void    GetScreenParameters (void)
  2062. {
  2063.     union REGS        r;
  2064.  
  2065. #  if (OS_SIZE == OS_16)
  2066.     MaximumColumns = *(int *)(0x0040004aL);
  2067. #  else
  2068.     MaximumColumns = *(short *)(0x044aL);
  2069. #  endif
  2070.  
  2071.     MaximumLines = 25;
  2072.  
  2073. /* Is this an EGA?  This test was found in NANSI.SYS */
  2074.  
  2075.     r.h.ah = 0x12;
  2076.     r.x.REG_BX = 0xff10;
  2077.     SystemInterrupt (0x10, &r, &r);
  2078.  
  2079. /* Else read the number of rows */
  2080.  
  2081.     if (!(r.x.REG_BX & 0xfefc))
  2082.     {
  2083.     r.x.REG_AX = 0x1130;
  2084.     r.h.bh = 0;
  2085.     SystemInterrupt (0x10, &r, &r);
  2086.     MaximumLines = r.h.dl + 1;
  2087.     }
  2088.  
  2089. /* Set up LINES and COLUMNS variables */
  2090.  
  2091.     SetVariableFromNumeric (LIT_LINES, (long)MaximumLines);
  2092.     SetVariableFromNumeric (LIT_COLUMNS, (long)MaximumColumns);
  2093. }
  2094. #endif
  2095.  
  2096. /* Ring Bell ? */
  2097.  
  2098. bool    RingWarningBell (void)
  2099. {
  2100.     if (KF_List[KF_RINGBELL].akey)
  2101. #if (OS_TYPE == OS_OS2)
  2102.     DosBeep (1380, 500);
  2103. #elif (OS_TYPE == OS_NT)
  2104.     Beep (1380, 500);
  2105. #else
  2106.     fputchar (0x07);
  2107.     fflush (stdout);
  2108. #endif
  2109.  
  2110.     return FALSE;
  2111. }
  2112.  
  2113. /*
  2114.  * Read keyboard function
  2115.  */
  2116.  
  2117. #if (OS_TYPE == OS_OS2)
  2118. unsigned char    ReadKeyBoard (unsigned char *f_key)
  2119. {
  2120.     KBDKEYINFO        kbci;
  2121.  
  2122.     *f_key = 0;
  2123.  
  2124. /* Wait for input */
  2125.  
  2126.     KbdCharIn (&kbci, IO_WAIT, 0);
  2127.  
  2128.     DisplayKeyCode (kbci.chChar, kbci.chScan);
  2129.  
  2130.     if (kbci.chChar == 0x03)
  2131.     raise (SIGINT);
  2132.  
  2133. /* Check for non-function character */
  2134.  
  2135.     if (kbci.chChar && (kbci.chChar != 0xe0))
  2136.     return (unsigned char)kbci.chChar;
  2137.  
  2138. /* Return scan code and type (normal or ALT'ed) */
  2139.  
  2140.     *f_key = (unsigned char)kbci.chScan;
  2141.     return (unsigned char)((kbci.fsState & (ALT | LEFTALT | RIGHTALT))
  2142.                ? KT_ALTFUNCTION
  2143.                : KT_FUNCTION);
  2144. }
  2145. #endif
  2146.  
  2147. /* NT Version */
  2148.  
  2149. #if (OS_TYPE == OS_NT)
  2150. unsigned char    ReadKeyBoard (unsigned char *f_key)
  2151. {
  2152.     INPUT_RECORD    Buffer;
  2153.     DWORD        NumberOfEventsRead;
  2154.     int            i;
  2155.  
  2156.     *f_key = 0;
  2157.  
  2158. /* Wait for input */
  2159.  
  2160.     while (TRUE)
  2161.     {
  2162.     if (!ReadConsoleInput (NT_StdIn, &Buffer, 1, &NumberOfEventsRead))
  2163.         continue;
  2164.  
  2165.     if (Buffer.EventType == WINDOW_BUFFER_SIZE_EVENT)
  2166.         return KT_RESIZE;
  2167.     
  2168. /* Ignore other non-keyboard events */
  2169.  
  2170.     if (Buffer.EventType != KEY_EVENT)
  2171.         continue;
  2172.  
  2173. /* Ignore key release events */
  2174.  
  2175.     if (!Buffer.Event.KeyEvent.bKeyDown)
  2176.         continue;
  2177.  
  2178. /* See if it is an ignore key? */
  2179.  
  2180.     for (i = 0; i < IGNORE_CNT; i++)
  2181.     {
  2182.         if (Buffer.Event.KeyEvent.wVirtualScanCode == IgnoreScanCode[i])
  2183.             break;
  2184.     }
  2185.  
  2186.     if (i != IGNORE_CNT)
  2187.         continue;
  2188.  
  2189. /* Keystroke mapping */
  2190.  
  2191.     if (DoNTKeyMap (&Buffer.Event.KeyEvent))
  2192.         break;
  2193.  
  2194. /* ? wRepeatCount */
  2195.  
  2196.     }
  2197.  
  2198.     DisplayKeyCode (Buffer.Event.KeyEvent.uChar.AsciiChar,
  2199.             Buffer.Event.KeyEvent.wVirtualScanCode);
  2200.  
  2201.     if (Buffer.Event.KeyEvent.uChar.AsciiChar == 0x03)
  2202.     raise (SIGINT);
  2203.  
  2204. /* Check for non-function character */
  2205.  
  2206.     if (Buffer.Event.KeyEvent.uChar.AsciiChar &&
  2207.     (Buffer.Event.KeyEvent.uChar.AsciiChar != 0xe0))
  2208.     return (unsigned char)Buffer.Event.KeyEvent.uChar.AsciiChar;
  2209.  
  2210. /* Return scan code and type (normal or ALT'ed) */
  2211.  
  2212.     *f_key = (unsigned char)Buffer.Event.KeyEvent.wVirtualScanCode;
  2213.     return (unsigned char)((Buffer.Event.KeyEvent.dwControlKeyState &
  2214.                     (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
  2215.                ? KT_ALTFUNCTION
  2216.                : KT_FUNCTION);
  2217. }
  2218.  
  2219. /*
  2220.  * Handle keyboard mapping
  2221.  */
  2222.  
  2223. static bool F_LOCAL  DoNTKeyMap (KEY_EVENT_RECORD *KeyEvent)
  2224. {
  2225.     int        i;
  2226.  
  2227.     if (KeyEvent->wVirtualScanCode == 0x0f)     /* TAB */
  2228.     {
  2229.     if (KeyEvent->dwControlKeyState & (CTRL_PRESSED | ALT_PRESSED))
  2230.         return FALSE;
  2231.     
  2232.     else if (KeyEvent->dwControlKeyState & SHIFT_PRESSED)
  2233.         KeyEvent->uChar.AsciiChar = 0;
  2234.  
  2235.     else
  2236.         KeyEvent->uChar.AsciiChar = CHAR_TAB;
  2237.         
  2238.     return TRUE;
  2239.     }
  2240.  
  2241.     else if ((KeyEvent->wVirtualScanCode == 0x0e) ||    /* BACKSPACE */
  2242.          (KeyEvent->wVirtualScanCode == 0x1c))     /* RETURN */
  2243.     return !C2bool (KeyEvent->dwControlKeyState & ALT_PRESSED);
  2244.  
  2245. /* All other mapped characters are OK */
  2246.  
  2247.     else if (KeyEvent->uChar.AsciiChar)
  2248.         return TRUE;
  2249.  
  2250. /* Handle function keys */
  2251.  
  2252.     for (i = 0; i < MAX_NT_FKMAP; i++)
  2253.     {
  2254.         if (KeyEvent->wVirtualScanCode != NT_KFMap [i].Normal)
  2255.         continue;
  2256.  
  2257. /* If Ctrl Alt pressed - ignore key */
  2258.  
  2259.     if ((KeyEvent->dwControlKeyState & (CTRL_PRESSED | ALT_PRESSED))
  2260.         == (CTRL_PRESSED | ALT_PRESSED))
  2261.         return FALSE;
  2262.  
  2263.     else if (KeyEvent->dwControlKeyState & CTRL_PRESSED)
  2264.         KeyEvent->wVirtualScanCode = NT_KFMap [i].Control;
  2265.  
  2266.     else if (KeyEvent->dwControlKeyState & ALT_PRESSED)
  2267.         KeyEvent->wVirtualScanCode = NT_KFMap [i].Alt;
  2268.  
  2269.     else if (KeyEvent->dwControlKeyState & SHIFT_PRESSED)
  2270.         KeyEvent->wVirtualScanCode = NT_KFMap [i].Shift;
  2271.     
  2272.     return TRUE;
  2273.     }
  2274.  
  2275.     return TRUE;
  2276. }
  2277. #endif
  2278.  
  2279. /* DOS Version */
  2280.  
  2281. #if (OS_TYPE == OS_DOS) 
  2282. unsigned char    ReadKeyBoard (unsigned char *f_key)
  2283. {
  2284.     unsigned char        a_key;
  2285.     union KeyCode {
  2286.     unsigned short        Key;
  2287.     struct Scan {
  2288.         unsigned char    ascii, scan;
  2289.     }            Scan;
  2290.     }                KeyCode;
  2291.  
  2292. /* If DEQSview is active - we must poll the keyboard */
  2293.  
  2294. #  if (OS_SIZE == OS_16)
  2295.     if (DESQviewActive)
  2296.     {
  2297.     if (!((KeyCode.Scan.ascii = Poll_Keyboard ())) ||
  2298.         (KeyCode.Scan.ascii == 0xe0))
  2299.         KeyCode.Scan.scan = Poll_Keyboard ();
  2300.     }
  2301.  
  2302.     else
  2303. #  endif
  2304.  
  2305. /*
  2306.  * Read Keyboard via interrupt 10 function 1 or 10 depending on whether we
  2307.  * have an extended keyboard or not!.
  2308.  */
  2309.  
  2310.     {
  2311.     KeyCode.Key = _bios_keybrd (ReadKeyboardOption);
  2312.  
  2313.     if (KeyCode.Scan.ascii == 0xe0)
  2314.         KeyCode.Scan.ascii = 0;
  2315.     }
  2316.  
  2317.     DisplayKeyCode (KeyCode.Scan.ascii, KeyCode.Scan.scan);
  2318.  
  2319. /* Check for interrupt */
  2320.  
  2321.     if (KeyCode.Scan.ascii == 3)
  2322.     raise (SIGINT);
  2323.  
  2324. /* Set up return values */
  2325.  
  2326.     if (KeyCode.Scan.ascii == 0)
  2327.     {
  2328.     a_key = KT_FUNCTION;
  2329.     *f_key = KeyCode.Scan.scan;
  2330.  
  2331. /* If ALT Key set, return 0xff instead of 0 for function key */
  2332.  
  2333.     if (_bios_keybrd (_KEYBRD_SHIFTSTATUS) & 0x08)
  2334.         a_key = KT_ALTFUNCTION;
  2335.     }
  2336.  
  2337. /* ASCII keycode - return it. */
  2338.  
  2339.     else
  2340.     {
  2341.     a_key = KeyCode.Scan.ascii;
  2342.     *f_key = 0;
  2343.     }
  2344.  
  2345.     return a_key;
  2346. }
  2347. #endif
  2348.  
  2349. #ifdef KEYDEBUG
  2350. static void    DisplayKeyCode (unsigned int a, unsigned int b)
  2351. {
  2352.     int        cp = ReadCursorPosition ();
  2353.  
  2354.     SetCursorPosition (23*80 + 59);
  2355.     printf ("ASCII %.2x SCAN %.2x\n", a, b);
  2356.     SetCursorPosition (cp);
  2357. }
  2358. #endif
  2359.  
  2360. /*
  2361.  * Update Initialisation value
  2362.  */
  2363.  
  2364. bool    ChangeInitialisationValue (char *string, int newvalue)
  2365. {
  2366.     int        i;
  2367.  
  2368.     for (i = KF_END_FKEYS; i < KF_LENGTH; ++i)
  2369.     {
  2370.     if (stricmp (string, KF_List[i].kf_name) == 0)
  2371.     {
  2372.         KF_List[i].akey = (char)newvalue;
  2373.         return TRUE;
  2374.     }
  2375.     }
  2376.  
  2377.     return FALSE;
  2378. }
  2379.  
  2380. /*
  2381.  * Enable keyboard polling function - required if DESQview loaded
  2382.  */
  2383.  
  2384. #if (OS_TYPE == OS_DOS)
  2385. static void F_LOCAL CheckKeyboardPolling (void)
  2386. {
  2387.     static bool        Initialised = FALSE;
  2388.     union REGS        r;
  2389.     int            i;
  2390.  
  2391.     if (Initialised)
  2392.     return;
  2393.     
  2394.     Initialised = TRUE;
  2395.  
  2396. /* Check to see we are running under DESQview */
  2397.  
  2398. #  if (OS_SIZE == OS_16)
  2399.     r.x.REG_AX = 0x2b01;
  2400.     r.x.REG_CX = 0x4445;
  2401.     r.x.REG_DX = 0x5351;
  2402.     DosInterrupt (&r, &r);
  2403.  
  2404.     if (r.h.al != 0xff)
  2405.     DESQviewActive = TRUE;
  2406. #  endif
  2407.  
  2408. /* Otherwise check for extended keyboard.  Stick 0xffff in the keyboard
  2409.  * buffer and read it back.  If we find it - OK!
  2410.  */
  2411.  
  2412.     ReadKeyboardOption = _KEYBRD_READ;    /* Normal keyboard        */
  2413.  
  2414.     r.h.ah = 0x05;
  2415.     r.x.REG_CX = 0xffff;
  2416.     SystemInterrupt (0x16, &r, &r);
  2417.  
  2418.     if (r.h.al)
  2419.     return;
  2420.  
  2421. /* 16 attempts to read extended keyboard interface */
  2422.  
  2423.     for (i = 0; i < 16; i++)
  2424.     {
  2425.     if ((unsigned)_bios_keybrd (_NKEYBRD_READ) == 0xffff)
  2426.     {
  2427.         ReadKeyboardOption = _NKEYBRD_READ;    /* Extended keyboard    */
  2428.         return;
  2429.     }
  2430.     }
  2431. }
  2432. #endif
  2433.  
  2434. /*
  2435.  * Print a single history entry
  2436.  */
  2437.  
  2438. static void F_LOCAL PrintOutHistory (FILE        *fp,
  2439.                      bool        n_flag,
  2440.                      struct cmd_history *cmd)
  2441. {
  2442.     char    *cp = cmd->command;
  2443.  
  2444.     if (n_flag)
  2445.     {
  2446.     fprintf (fp, "%5d: ", cmd->number);
  2447.  
  2448.     while (*cp)
  2449.     {
  2450.         putc (*cp, fp);
  2451.  
  2452.         if (*(cp++) == CHAR_NEW_LINE)
  2453.         fputs ("       ", fp);
  2454.     }
  2455.     }
  2456.  
  2457.     else
  2458.     fputs (cp, fp);
  2459.  
  2460.     putc (CHAR_NEW_LINE, fp);
  2461. }
  2462.  
  2463. /*
  2464.  * Get the last history event number
  2465.  */
  2466.  
  2467. int GetLastHistoryEvent (void)
  2468. {
  2469.     return (l_history) ? cmd_history[l_history - 1].number + 1 : 1;
  2470. }
  2471.  
  2472. /*
  2473.  * Get the last history event number
  2474.  */
  2475.  
  2476. int GetFirstHistoryEvent (void)
  2477. {
  2478.     return (cmd_history[0].number) ? cmd_history[0].number : 1;
  2479. }
  2480.  
  2481. /*
  2482.  * Get the last history event
  2483.  */
  2484.  
  2485. #if (OS_TYPE != OS_DOS) 
  2486. char *GetLastHistoryString (void)
  2487. {
  2488.     return l_history ? cmd_history[l_history - 1].command : (char *)NULL;
  2489. }
  2490. #endif
  2491.  
  2492. /*
  2493.  * Dump history
  2494.  */
  2495.  
  2496. void PrintHistory (bool r_flag, bool n_flag, int First, int Last, FILE *fp)
  2497. {
  2498.     int        i;
  2499.  
  2500.     if (r_flag)
  2501.     {
  2502.     for (i = l_history - 1;
  2503.          (i >= 0) && (cmd_history[i].number >= First); --i)
  2504.     {
  2505.         if (cmd_history[i].number <= Last)
  2506.         PrintOutHistory (fp, n_flag, &cmd_history[i]);
  2507.     }
  2508.     }
  2509.  
  2510.     else
  2511.     {
  2512.     for (i = 0; (i < l_history) && (cmd_history[i].number <= Last); ++i)
  2513.     {
  2514.         if (cmd_history[i].number >= First)
  2515.         PrintOutHistory (fp, n_flag, &cmd_history[i]);
  2516.     }
  2517.     }
  2518. }
  2519.  
  2520. /*
  2521.  * Search for an event
  2522.  */
  2523.  
  2524. int SearchHistory (char *buffer)
  2525. {
  2526.     int        Length = strlen (buffer);
  2527.     int        i;
  2528.  
  2529.     for (i = l_history - 1;
  2530.      (i >= 0) && strncmp (buffer, cmd_history[i].command, Length); --i)
  2531.     continue;
  2532.  
  2533.     return (i == -1) ? -1 : cmd_history[i].number;
  2534. }
  2535.  
  2536. /*
  2537.  * Release Command
  2538.  */
  2539.  
  2540. static void F_LOCAL ReleaseCommandMemory (struct cmd_history *cp)
  2541. {
  2542.     if (cp->command != null)
  2543.     ReleaseMemoryCell ((void *)cp->command);
  2544. }
  2545.  
  2546. /*
  2547.  * Flush history buffer.  If save is set, the contents of the console
  2548.  * buffer will be saved.
  2549.  */
  2550.  
  2551. void    FlushHistoryBuffer (void)
  2552. {
  2553.     if (SaveHistory)
  2554.     AddHistory (AppendHistory);
  2555.  
  2556.     memset (ConsoleLineBuffer, 0, LINE_MAX + 1);
  2557.  
  2558.     AppendHistory = FALSE;
  2559.     SaveHistory = FALSE;
  2560. }
  2561.  
  2562. /*
  2563.  * Save the current console buffer
  2564.  */
  2565.  
  2566. static void F_LOCAL SaveCurrentHistory (void)
  2567. {
  2568.     c_history = l_history;
  2569.  
  2570.     if (SaveHistory)
  2571.     AddHistory (AppendHistory);
  2572.  
  2573.     AppendHistory = (bool)(LastUserPrompt == PS2);
  2574.     SaveHistory = (bool)((LastUserPrompt == PS1) || AppendHistory);
  2575. }
  2576.  
  2577. /*
  2578.  * Insert a Character into the buffer
  2579.  */
  2580.  
  2581. static bool F_LOCAL InsertACharacter (int NewCharacter)
  2582. {
  2583.     if ((EndOfCurrentLine - ConsoleLineBuffer) == LINE_MAX)
  2584.     return RingWarningBell ();    /* Ring bell - line full    */
  2585.  
  2586.     if (c_buffer_pos != EndOfCurrentLine)
  2587.     memrcpy (EndOfCurrentLine + 1, EndOfCurrentLine,
  2588.          EndOfCurrentLine - c_buffer_pos + 1);
  2589.  
  2590.     ++EndOfCurrentLine;
  2591.  
  2592. /* Fast end of line processing */
  2593.  
  2594.     if ((c_buffer_pos == EndOfCurrentLine - 1) && (NewCharacter != CHAR_TAB))
  2595.     {
  2596.     *(c_buffer_pos++) = (char)NewCharacter;
  2597.     OutputACharacter (NewCharacter);
  2598.     return FALSE;
  2599.     }
  2600.  
  2601. /* Not at end of line - redraw */
  2602.  
  2603.     *(c_buffer_pos++) = (char)NewCharacter;
  2604.     return TRUE;
  2605. }
  2606.  
  2607. /*
  2608.  * Delete Last History Item
  2609.  */
  2610.  
  2611. void DeleteLastHistory (void)
  2612. {
  2613.     if (l_history)
  2614.     ReleaseCommandMemory (&cmd_history[--l_history]);
  2615. }
  2616.  
  2617. /*
  2618.  * Clear the screen
  2619.  */
  2620.  
  2621. #if (OS_TYPE == OS_OS2)
  2622. bool    ClearScreen (void)
  2623. {
  2624.     BYTE    abCell[2];
  2625.     USHORT    usRow;
  2626.     USHORT    usColumn;
  2627.     USHORT    cb = sizeof (abCell);
  2628.  
  2629.     fputchar (CHAR_NEW_LINE);
  2630.     FlushStreams ();
  2631.  
  2632. /* Read attribute under cursor */
  2633.  
  2634.     VioGetCurPos (&usRow, &usColumn, 0);
  2635.     VioReadCellStr (abCell, &cb , usRow, usColumn, 0);
  2636.  
  2637.     abCell[0] = CHAR_SPACE;
  2638.  
  2639.     VioScrollUp (0, 0, 0xffff, 0xffff, 0xffff, abCell, 0);
  2640.     VioSetCurPos (0, 0, 0);
  2641.  
  2642.     OutputUserPrompt (LastUserPrompt);
  2643.     StartCursorPosition = ReadCursorPosition ();
  2644.     return TRUE;
  2645. }
  2646. #endif
  2647.  
  2648. /*
  2649.  * NT Version
  2650.  */
  2651.  
  2652. #if (OS_TYPE == OS_NT)
  2653. bool    ClearScreen (void)
  2654. {
  2655.     WORD            Atts[2];
  2656.     CONSOLE_SCREEN_BUFFER_INFO    CSI;
  2657.     DWORD            ActionCount;
  2658.     CHAR_INFO            *Buffer;
  2659.     COORD            dwBufferSize;
  2660.     COORD            dwBufferCoord;
  2661.     SMALL_RECT            WriteRegion;
  2662.     DWORD            Size = MaximumColumns * MaximumLines;
  2663.  
  2664.     FlushStreams ();
  2665.  
  2666. /* Read attribute under cursor */
  2667.  
  2668.     GetConsoleScreenBufferInfo (NT_StdOut, &CSI);
  2669.     ReadConsoleOutputAttribute (NT_StdOut, Atts, 1, CSI.dwCursorPosition,
  2670.                     &ActionCount);
  2671.  
  2672. /*
  2673.  * Write it.  What a pain!!!
  2674.  *
  2675.  * Get some memory
  2676.  */
  2677.  
  2678.     Buffer = (CHAR_INFO *)AllocateMemoryCell (Size * sizeof (CHAR_INFO));
  2679.  
  2680. /* Set up attributes */
  2681.  
  2682.     for (ActionCount = 0; ActionCount < Size; ActionCount++)
  2683.     {
  2684.     Buffer[ActionCount].Attributes = Atts[0];
  2685.     Buffer[ActionCount].Char.AsciiChar = CHAR_SPACE;
  2686.     }
  2687.  
  2688. /* Size */
  2689.  
  2690.     dwBufferSize.X = MaximumColumns;
  2691.     dwBufferSize.Y = MaximumLines;
  2692.  
  2693. /* Co-ordinated */
  2694.  
  2695.     dwBufferCoord.X = 0;
  2696.     dwBufferCoord.Y = 0;
  2697.  
  2698. /* Set up output data */
  2699.  
  2700.     WriteRegion.Left = 0;
  2701.     WriteRegion.Top = 0;
  2702.     WriteRegion.Right = MaximumColumns - 1;
  2703.     WriteRegion.Bottom = MaximumLines - 1;
  2704.  
  2705.     WriteConsoleOutput (NT_StdOut, Buffer, dwBufferSize, dwBufferCoord,
  2706.             &WriteRegion);
  2707.  
  2708.     ReleaseMemoryCell (Buffer);
  2709.  
  2710.     SetConsoleCursorPosition (NT_StdOut, dwBufferCoord);
  2711.  
  2712.     OutputUserPrompt (LastUserPrompt);
  2713.     StartCursorPosition = ReadCursorPosition ();
  2714.     return TRUE;
  2715. }
  2716. #endif
  2717.  
  2718. /* DOS Version */
  2719.  
  2720. #if (OS_TYPE == OS_DOS)
  2721. bool    ClearScreen (void)
  2722. {
  2723.     union REGS        r;
  2724.     unsigned char    backg;
  2725.  
  2726.     fputchar (CHAR_NEW_LINE);
  2727.     FlushStreams ();
  2728.  
  2729. /* Get the background attribute of the cursor */
  2730.  
  2731.     r.h.ah = 0x08;
  2732.     r.h.bh = 0;
  2733.     SystemInterrupt (0x10, &r, &r);
  2734.     backg = (unsigned char)(r.h.ah & 0x07);
  2735.  
  2736. /* Clear the screen */
  2737.  
  2738.     r.x.REG_AX = 0x0600;
  2739.     r.h.bh = backg;
  2740.     r.x.REG_CX = 0;
  2741.     r.h.dh = (unsigned char)MaximumLines;
  2742.     r.h.dl = (unsigned char)MaximumColumns;
  2743.     SystemInterrupt (0x10, &r, &r);
  2744.  
  2745. /* Position to top of page */
  2746.  
  2747.     r.h.ah = 0x02;                /* Set new position    */
  2748.     r.h.bh = 0;                    /* Page zero        */
  2749.     r.x.REG_DX = 0x0000;
  2750.     SystemInterrupt (0x10, &r, &r);
  2751.  
  2752.     OutputUserPrompt (LastUserPrompt);
  2753.     StartCursorPosition = ReadCursorPosition ();
  2754.     return TRUE;
  2755. }
  2756. #endif
  2757.  
  2758. /*
  2759.  * Display a line, handling control characters
  2760.  */
  2761.  
  2762. void    DisplayLineWithControl (char *line)
  2763. {
  2764.     int        off = ReadCursorPosition ();
  2765.  
  2766. /* Print characters */
  2767.  
  2768.     while (*line)
  2769.     {
  2770.  
  2771. /* Process TABS */
  2772.  
  2773.     if (*line == CHAR_TAB)
  2774.     {
  2775.         do
  2776.         {
  2777.         fputchar (CHAR_SPACE);
  2778.         } while ((++off) % 8);
  2779.     }
  2780.  
  2781. /* Process Control and printing characters */
  2782.  
  2783.     else
  2784.         off += OutputACharacter (*line);
  2785.  
  2786.     ++line;
  2787.     }
  2788. }
  2789.  
  2790. /*
  2791.  * Get the Root Disk Drive.  If not defined, set it to the current drive.
  2792.  */
  2793.  
  2794. #if (OS_TYPE != OS_UNIX)
  2795. int    GetRootDiskDrive (void)
  2796. {
  2797.     if (!KF_List[KF_ROOTDRIVE].akey)
  2798.     KF_List[KF_ROOTDRIVE].akey = (char)GetCurrentDrive ();
  2799.  
  2800.     return KF_List[KF_ROOTDRIVE].akey;
  2801. }
  2802. #endif
  2803.  
  2804. /*
  2805.  * Get the EOF Key
  2806.  */
  2807.  
  2808. int    GetEOFKey (void)
  2809. {
  2810. #if (OS_TYPE == OS_UNIX)
  2811.     struct termios    ts;
  2812.  
  2813.     return tcgetattr (1, &ts) ? 4 : ts.c_cc[VEOF];
  2814. #else
  2815.     if (!KF_List[KF_EOFKEY].akey)
  2816.     KF_List[KF_EOFKEY].akey = 0x1a;
  2817.  
  2818.     return KF_List[KF_EOFKEY].akey;
  2819. #endif
  2820. }
  2821.  
  2822. /*
  2823.  * Output a Character - excluding TABS.  Return # chars output.
  2824.  *
  2825.  * TABS are not checked for
  2826.  */
  2827.  
  2828. static int F_LOCAL OutputACharacter (int c)
  2829. {
  2830.     int        off = 1;
  2831.  
  2832. /* Check for control and process */
  2833.  
  2834.     if (iscntrl (c))
  2835.     {
  2836.     fputchar (CHAR_NOT);
  2837.     c += '@';
  2838.     off++;
  2839.     }
  2840.  
  2841. /* Output the character */
  2842.  
  2843.     fputchar (c);
  2844.     return off;
  2845. }
  2846.  
  2847. /*
  2848.  * Strip off trailing EOFs and EOLs from console buffer
  2849.  */
  2850.  
  2851. char    CleanUpBuffer (int length, char *buffer, int eofc)
  2852. {
  2853.     char    *cp = &buffer[length - 1];
  2854.     char    ret;
  2855.  
  2856.     while (length && ((*cp == (char)eofc) || (*cp == CHAR_NEW_LINE)))
  2857.     {
  2858.     length--;
  2859.     cp--;
  2860.     }
  2861.  
  2862.     ret = *(cp + 1);
  2863.     *(cp + 1) = 0;
  2864.     return ret;
  2865. }
  2866.  
  2867. /*
  2868.  * Look up the keystroke to see if it is one of our functions
  2869.  */
  2870.  
  2871. int    LookUpKeyBoardFunction (unsigned char a_key, unsigned char f_key)
  2872. {
  2873.     int        i;
  2874.  
  2875.     for (i = 0; (i < KF_END_FKEYS); ++i)
  2876.     {
  2877.     if (KF_List[i].akey != a_key)
  2878.         continue;
  2879.  
  2880. /* Function or meta key? */
  2881.  
  2882.     if ((a_key != KT_FUNCTION) && (a_key != KT_ALTFUNCTION))
  2883.         break;
  2884.  
  2885.     else if (KF_List[i].fkey == f_key)
  2886.         break;
  2887.     }
  2888.  
  2889. /* If this is a function key and is not ours, ignore it */
  2890.  
  2891.     if ((i == KF_END_FKEYS) && ((a_key == KT_FUNCTION) ||
  2892.                     (a_key == KT_ALTFUNCTION)))
  2893.     return 0;
  2894.  
  2895.     return (i == KF_END_FKEYS) ? (int)a_key
  2896.                        : -((int)(KF_List[i].fcode) + 1);
  2897. }
  2898.  
  2899. /*
  2900.  * Build a list of filenames for completion
  2901.  */
  2902.  
  2903. char     **BuildCompletionList (char *String, size_t Length, int *Count,
  2904.                    bool Full)
  2905. {
  2906.     char    *MatchString = GetAllocatedSpace (Length + 2);
  2907.     char    **FileList;
  2908.     char    *vecp[2];
  2909.     char    *cp;
  2910.     char    **ap;
  2911.     size_t    DiscardLength;
  2912.  
  2913. /* Build the string to expand */
  2914.  
  2915.     *Count = 0;
  2916.     memmove (MatchString, String, Length);
  2917.  
  2918.     if (MatchString[Length - 1] != CHAR_MATCH_ALL)
  2919.     {
  2920.     MatchString[Length] = CHAR_MATCH_ALL;
  2921.     MatchString[Length + 1] = 0;
  2922.     }
  2923.  
  2924.     else
  2925.     MatchString[Length] = 0;
  2926.  
  2927.     vecp[0] = MatchString;
  2928.     vecp[1] = (char *)NULL;
  2929.  
  2930. /* Expand it */
  2931.  
  2932.     FileList = ExpandWordList (vecp, EXPAND_SPLITIFS | EXPAND_GLOBBING |
  2933.                     EXPAND_TILDE, (ExeMode *)NULL);
  2934.  
  2935. /* Check to see if it expanded */
  2936.  
  2937.     if ((strcmp (FileList[0], MatchString) == 0) &&
  2938.     (FileList[1] == (char *) NULL))
  2939.     {
  2940.     ReleaseMemoryCell (FileList[0]);
  2941.     ReleaseMemoryCell (FileList);
  2942.         FileList = (char **)NULL;
  2943.     }
  2944.  
  2945.     ReleaseMemoryCell (MatchString);
  2946.  
  2947.     if (FileList != (char **)NULL)
  2948.     *Count = CountNumberArguments (FileList);
  2949.  
  2950. /* Exit if expansion failed or we don't want directory stripping */
  2951.  
  2952.     if ((FileList == (char **)NULL) || Full)
  2953.     return FileList;
  2954.  
  2955. /* Strip off directory name ..../ or x: */
  2956.  
  2957.     if ((cp = FindLastPathCharacter (FileList[0])) != (char *)NULL)
  2958.         cp++;
  2959.  
  2960.     else if (IsDriveCharacter (FileList[0][1]))
  2961.         cp = &FileList[0][2];
  2962.  
  2963.     else
  2964.         return FileList;
  2965.  
  2966. /* Get the discard length and remove it from the strings */
  2967.  
  2968.     DiscardLength = cp - FileList[0];
  2969.     ap = FileList;
  2970.  
  2971.     while ((cp = *(ap++)) != (char *)NULL)
  2972.         strcpy (cp, cp + DiscardLength);
  2973.  
  2974.     return FileList;
  2975. }
  2976.  
  2977. /*
  2978.  * Get the Common part of the name from a list of files
  2979.  */
  2980.  
  2981. size_t    GetCommonPartOfFileList (char **FileList)
  2982. {
  2983.     char    **ap = FileList + 1;
  2984.     char    *BaseName = *FileList;
  2985.     size_t    maxi = strlen (*FileList);
  2986.     size_t    i;
  2987.  
  2988. /* Scan the list */
  2989.  
  2990.     while (*ap != (char *)NULL)
  2991.     {
  2992.     for (i = 0; (BaseName[i] == (*ap)[i]) && (i < maxi); i++)
  2993.          continue;
  2994.  
  2995.     BaseName[maxi = i] = 0;
  2996.     ap++;
  2997.     }
  2998.  
  2999.     return maxi;
  3000. }
  3001.  
  3002. /*
  3003.  * Return the function key information associated with an internal key
  3004.  * function
  3005.  */
  3006.  
  3007. #if defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
  3008. unsigned char    GetFunctionKeyMap (int key, unsigned char *f_key)
  3009. {
  3010.     *f_key = KF_List[key].fkey;
  3011.     return KF_List[key].akey;
  3012. }
  3013. #endif
  3014.  
  3015. /*
  3016.  * Change Keyboard to RAW/COOKED mode
  3017.  */
  3018.  
  3019. #if (OS_TYPE == OS_OS2)
  3020. static void F_LOCAL    ChangeKeyboardMode (bool Cooked)
  3021. {
  3022.     KBDINFO        kbstInfo;
  3023.  
  3024. /* Get current mode */
  3025.  
  3026.     kbstInfo.cb = sizeof (kbstInfo);
  3027.     KbdGetStatus (&kbstInfo, 0);
  3028.  
  3029. /* Change it */
  3030.  
  3031.     kbstInfo.fsMask &= ~(KEYBOARD_ASCII_MODE | KEYBOARD_ECHO_ON |
  3032.                  KEYBOARD_ECHO_OFF   | KEYBOARD_BINARY_MODE);
  3033.  
  3034.     kbstInfo.fsMask |= (Cooked) ? (KEYBOARD_ASCII_MODE | KEYBOARD_ECHO_ON)
  3035.                     : (KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE);
  3036.  
  3037.     KbdSetStatus (&kbstInfo, 0);
  3038. }
  3039. #endif
  3040.  
  3041. /* NT Version */
  3042.  
  3043. #if (OS_TYPE == OS_NT)
  3044. static void F_LOCAL    ChangeKeyboardMode (bool Cooked)
  3045. {
  3046.     DWORD        NewMode = ENABLE_WINDOW_INPUT;
  3047.  
  3048. /* Get handlers */
  3049.  
  3050.     NT_StdIn  = GetStdHandle (STD_INPUT_HANDLE);
  3051.     NT_StdOut = GetStdHandle (STD_OUTPUT_HANDLE);
  3052.  
  3053. /* Set up cooked mode if required */
  3054.  
  3055.     if (Cooked)
  3056.     NewMode = (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
  3057.            ENABLE_ECHO_INPUT);
  3058.  
  3059. /* Change modes */
  3060.  
  3061.     SetConsoleMode (NT_StdIn, NewMode);
  3062.     SetConsoleMode (NT_StdOut, ENABLE_PROCESSED_OUTPUT |
  3063.                    ENABLE_WRAP_AT_EOL_OUTPUT);
  3064. }
  3065. #endif
  3066.  
  3067. /* UNIX Version */
  3068.  
  3069. #if (OS_TYPE == OS_UNIX)
  3070. static void F_LOCAL    ChangeKeyboardMode (bool Cooked)
  3071. {
  3072.     fputs ("UNIX: ChangeKeyboardMode NI\n", stderr);
  3073. }
  3074. #endif
  3075.  
  3076. /*
  3077.  * EMX needs a read keyboard function
  3078.  */
  3079.  
  3080. #if (OS_TYPE == OS_DOS) && defined (__EMX__)
  3081. unsigned int     _bios_keybrd (unsigned int function)
  3082. {
  3083.     union REGS        r;
  3084.  
  3085.     r.h.ah = function;
  3086.     SystemInterrupt (0x16, &r, &r);
  3087.     return r.x.REG_AX;
  3088. }
  3089. #endif
  3090.